Merge branch 'hotfix' into site_sync

This commit is contained in:
sahil28297
2019-04-14 18:58:28 +05:30
committed by GitHub
63 changed files with 3523 additions and 2426 deletions

View File

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

View File

@@ -6,6 +6,7 @@ import frappe, erpnext
from frappe import _ from frappe import _
from frappe.utils import flt, fmt_money, getdate, formatdate from frappe.utils import flt, fmt_money, getdate, formatdate
from frappe.model.document import Document from frappe.model.document import Document
from frappe.model.meta import get_field_precision
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
from erpnext.accounts.utils import get_account_currency from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
@@ -56,7 +57,7 @@ class GLEntry(Document):
.format(self.voucher_type, self.voucher_no, self.account)) .format(self.voucher_type, self.voucher_no, self.account))
# Zero value transaction is not allowed # Zero value transaction is not allowed
if not (flt(self.debit) or flt(self.credit)): if not (flt(self.debit, self.precision("debit")) or flt(self.credit, self.precision("credit"))):
frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}") frappe.throw(_("{0} {1}: Either debit or credit amount is required for {2}")
.format(self.voucher_type, self.voucher_no, self.account)) .format(self.voucher_type, self.voucher_no, self.account))
@@ -216,17 +217,23 @@ def validate_frozen_account(account, adv_adj=None):
def update_against_account(voucher_type, voucher_no): def update_against_account(voucher_type, voucher_no):
entries = frappe.db.get_all("GL Entry", entries = frappe.db.get_all("GL Entry",
filters={"voucher_type": voucher_type, "voucher_no": voucher_no}, filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
fields=["name", "party", "against", "debit", "credit", "account"]) fields=["name", "party", "against", "debit", "credit", "account", "company"])
if not entries:
return
company_currency = erpnext.get_company_currency(entries[0].company)
precision = get_field_precision(frappe.get_meta("GL Entry")
.get_field("debit"), company_currency)
accounts_debited, accounts_credited = [], [] accounts_debited, accounts_credited = [], []
for d in entries: for d in entries:
if flt(d.debit > 0): accounts_debited.append(d.party or d.account) if flt(d.debit, precision) > 0: accounts_debited.append(d.party or d.account)
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account) if flt(d.credit, precision) > 0: accounts_credited.append(d.party or d.account)
for d in entries: for d in entries:
if flt(d.debit > 0): if flt(d.debit, precision) > 0:
new_against = ", ".join(list(set(accounts_credited))) new_against = ", ".join(list(set(accounts_credited)))
if flt(d.credit > 0): if flt(d.credit, precision) > 0:
new_against = ", ".join(list(set(accounts_debited))) new_against = ", ".join(list(set(accounts_debited)))
if d.against != new_against: if d.against != new_against:

View File

@@ -232,6 +232,13 @@ frappe.ui.form.on('Payment Entry', {
}, },
party_type: function(frm) { party_type: function(frm) {
let party_types = Object.keys(frappe.boot.party_account_types);
if(frm.doc.party_type && !party_types.includes(frm.doc.party_type)){
frm.set_value("party_type", "");
frappe.throw(__("Party can only be one of "+ party_types.join(", ")));
}
if(frm.doc.party) { if(frm.doc.party) {
$.each(["party", "party_balance", "paid_from", "paid_to", $.each(["party", "party_balance", "paid_from", "paid_to",
"paid_from_account_currency", "paid_from_account_balance", "paid_from_account_currency", "paid_from_account_balance",

View File

@@ -20,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "type_of_payment", "fieldname": "type_of_payment",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -53,6 +54,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -86,6 +88,7 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_type", "fieldname": "payment_type",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -119,6 +122,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_5", "fieldname": "column_break_5",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -151,6 +155,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Today", "default": "Today",
"fetch_if_empty": 0,
"fieldname": "posting_date", "fieldname": "posting_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -183,6 +188,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -216,6 +222,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -249,6 +256,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "mode_of_payment", "fieldname": "mode_of_payment",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -283,6 +291,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)", "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)",
"fetch_if_empty": 0,
"fieldname": "party_section", "fieldname": "party_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -317,6 +326,7 @@
"columns": 0, "columns": 0,
"default": "", "default": "",
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.docstatus==0", "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.docstatus==0",
"fetch_if_empty": 0,
"fieldname": "party_type", "fieldname": "party_type",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -351,6 +361,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type",
"fetch_if_empty": 0,
"fieldname": "party", "fieldname": "party",
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"hidden": 0, "hidden": 0,
@@ -386,6 +397,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type", "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.party_type",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "party_name", "fieldname": "party_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -418,6 +430,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_11", "fieldname": "column_break_11",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -450,6 +463,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "party", "depends_on": "party",
"fetch_if_empty": 0,
"fieldname": "bank_account", "fieldname": "bank_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -476,40 +490,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "contact_person",
"fieldname": "contact_email",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Email",
"length": 0,
"no_copy": 0,
"options": "Email",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@@ -518,6 +498,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "party", "depends_on": "party",
"fetch_if_empty": 0,
"fieldname": "contact_person", "fieldname": "contact_person",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -544,6 +525,41 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "contact_person",
"fetch_if_empty": 0,
"fieldname": "contact_email",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Email",
"length": 0,
"no_copy": 0,
"options": "Email",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@@ -551,6 +567,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_accounts_section", "fieldname": "payment_accounts_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -584,6 +601,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "party", "depends_on": "party",
"fetch_if_empty": 0,
"fieldname": "party_balance", "fieldname": "party_balance",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -617,6 +635,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(in_list([\"Internal Transfer\", \"Pay\"], doc.payment_type) || doc.party)", "depends_on": "eval:(in_list([\"Internal Transfer\", \"Pay\"], doc.payment_type) || doc.party)",
"fetch_if_empty": 0,
"fieldname": "paid_from", "fieldname": "paid_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -651,6 +670,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "paid_from", "depends_on": "paid_from",
"fetch_if_empty": 0,
"fieldname": "paid_from_account_currency", "fieldname": "paid_from_account_currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -685,6 +705,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "paid_from", "depends_on": "paid_from",
"fetch_if_empty": 0,
"fieldname": "paid_from_account_balance", "fieldname": "paid_from_account_balance",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -718,6 +739,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_18", "fieldname": "column_break_18",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -750,6 +772,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(in_list([\"Internal Transfer\", \"Receive\"], doc.payment_type) || doc.party)", "depends_on": "eval:(in_list([\"Internal Transfer\", \"Receive\"], doc.payment_type) || doc.party)",
"fetch_if_empty": 0,
"fieldname": "paid_to", "fieldname": "paid_to",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -784,6 +807,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "paid_to", "depends_on": "paid_to",
"fetch_if_empty": 0,
"fieldname": "paid_to_account_currency", "fieldname": "paid_to_account_currency",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -818,6 +842,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "paid_to", "depends_on": "paid_to",
"fetch_if_empty": 0,
"fieldname": "paid_to_account_balance", "fieldname": "paid_to_account_balance",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -853,6 +878,7 @@
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_to && doc.paid_from)", "depends_on": "eval:(doc.paid_to && doc.paid_from)",
"fetch_if_empty": 0,
"fieldname": "payment_amounts_section", "fieldname": "payment_amounts_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -886,6 +912,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "paid_amount", "fieldname": "paid_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -920,6 +947,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "source_exchange_rate", "fieldname": "source_exchange_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -953,6 +981,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "base_paid_amount", "fieldname": "base_paid_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -986,6 +1015,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_21", "fieldname": "column_break_21",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1018,6 +1048,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "received_amount", "fieldname": "received_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1052,6 +1083,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "target_exchange_rate", "fieldname": "target_exchange_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1085,6 +1117,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "base_received_amount", "fieldname": "base_received_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1120,6 +1153,7 @@
"collapsible_depends_on": "references", "collapsible_depends_on": "references",
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.party && doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)", "depends_on": "eval:(doc.party && doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
"fetch_if_empty": 0,
"fieldname": "section_break_14", "fieldname": "section_break_14",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1154,6 +1188,7 @@
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"depends_on": "eval:in_list(['Pay', 'Receive'], doc.payment_type)", "depends_on": "eval:in_list(['Pay', 'Receive'], doc.payment_type)",
"fetch_if_empty": 0,
"fieldname": "allocate_payment_amount", "fieldname": "allocate_payment_amount",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1187,6 +1222,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "references", "fieldname": "references",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1221,6 +1257,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "section_break_34", "fieldname": "section_break_34",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1254,6 +1291,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_amount && doc.received_amount && doc.references)", "depends_on": "eval:(doc.paid_amount && doc.received_amount && doc.references)",
"fetch_if_empty": 0,
"fieldname": "total_allocated_amount", "fieldname": "total_allocated_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1287,6 +1325,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "base_total_allocated_amount", "fieldname": "base_total_allocated_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1320,6 +1359,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "set_exchange_gain_loss", "fieldname": "set_exchange_gain_loss",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
@@ -1352,6 +1392,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_36", "fieldname": "column_break_36",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1384,6 +1425,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_amount && doc.received_amount && doc.references)", "depends_on": "eval:(doc.paid_amount && doc.received_amount && doc.references)",
"fetch_if_empty": 0,
"fieldname": "unallocated_amount", "fieldname": "unallocated_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1417,6 +1459,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_amount && doc.received_amount)", "depends_on": "eval:(doc.paid_amount && doc.received_amount)",
"fetch_if_empty": 0,
"fieldname": "difference_amount", "fieldname": "difference_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -1451,6 +1494,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "difference_amount", "depends_on": "difference_amount",
"fetch_if_empty": 0,
"fieldname": "write_off_difference_amount", "fieldname": "write_off_difference_amount",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
@@ -1485,6 +1529,7 @@
"collapsible_depends_on": "deductions", "collapsible_depends_on": "deductions",
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_amount && doc.received_amount)", "depends_on": "eval:(doc.paid_amount && doc.received_amount)",
"fetch_if_empty": 0,
"fieldname": "deductions_or_loss_section", "fieldname": "deductions_or_loss_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1517,6 +1562,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "deductions", "fieldname": "deductions",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1550,6 +1596,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "transaction_references", "fieldname": "transaction_references",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1583,6 +1630,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_from && doc.paid_to)", "depends_on": "eval:(doc.paid_from && doc.paid_to)",
"fetch_if_empty": 0,
"fieldname": "reference_no", "fieldname": "reference_no",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -1615,6 +1663,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_23", "fieldname": "column_break_23",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1647,6 +1696,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_from && doc.paid_to)", "depends_on": "eval:(doc.paid_from && doc.paid_to)",
"fetch_if_empty": 0,
"fieldname": "reference_date", "fieldname": "reference_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -1680,6 +1730,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.docstatus==1", "depends_on": "eval:doc.docstatus==1",
"fetch_if_empty": 0,
"fieldname": "clearance_date", "fieldname": "clearance_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -1714,6 +1765,7 @@
"collapsible_depends_on": "", "collapsible_depends_on": "",
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)", "depends_on": "eval:(doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
"fetch_if_empty": 0,
"fieldname": "section_break_12", "fieldname": "section_break_12",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1747,6 +1799,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "project", "fieldname": "project",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1780,6 +1833,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "remarks", "fieldname": "remarks",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -1812,6 +1866,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_16", "fieldname": "column_break_16",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1843,6 +1898,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "letter_head", "fieldname": "letter_head",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1876,6 +1932,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "print_heading", "fieldname": "print_heading",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1910,6 +1967,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "bank_account.bank", "fetch_from": "bank_account.bank",
"fetch_if_empty": 0,
"fieldname": "bank", "fieldname": "bank",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "hidden": 0,
@@ -1943,6 +2001,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "bank_account.bank_account_no", "fetch_from": "bank_account.bank_account_no",
"fetch_if_empty": 0,
"fieldname": "bank_account_no", "fieldname": "bank_account_no",
"fieldtype": "Read Only", "fieldtype": "Read Only",
"hidden": 0, "hidden": 0,
@@ -1975,6 +2034,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "payment_order", "fieldname": "payment_order",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2008,6 +2068,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "subscription_section", "fieldname": "subscription_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2040,6 +2101,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "auto_repeat", "fieldname": "auto_repeat",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2073,6 +2135,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "amended_from", "fieldname": "amended_from",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2105,6 +2168,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "title", "fieldname": "title",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -2141,7 +2205,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2019-01-15 15:58:40.742601", "modified": "2019-03-27 17:39:54.163016",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Entry", "name": "Payment Entry",

View File

@@ -536,9 +536,13 @@ class PaymentEntry(AccountsController):
@frappe.whitelist() @frappe.whitelist()
def get_outstanding_reference_documents(args): def get_outstanding_reference_documents(args):
if isinstance(args, string_types): if isinstance(args, string_types):
args = json.loads(args) args = json.loads(args)
if args.get('party_type') == 'Member':
return
# confirm that Supplier is not blocked # confirm that Supplier is not blocked
if args.get('party_type') == 'Supplier': if args.get('party_type') == 'Supplier':
supplier_status = get_supplier_block_status(args['party']) supplier_status = get_supplier_block_status(args['party'])
@@ -749,7 +753,7 @@ def get_outstanding_on_journal_entry(name):
@frappe.whitelist() @frappe.whitelist()
def get_reference_details(reference_doctype, reference_name, party_account_currency): def get_reference_details(reference_doctype, reference_name, party_account_currency):
total_amount = outstanding_amount = exchange_rate = None total_amount = outstanding_amount = exchange_rate = bill_no = None
ref_doc = frappe.get_doc(reference_doctype, reference_name) ref_doc = frappe.get_doc(reference_doctype, reference_name)
company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company) company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company)
@@ -783,6 +787,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
if reference_doctype in ("Sales Invoice", "Purchase Invoice"): if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
outstanding_amount = ref_doc.get("outstanding_amount") outstanding_amount = ref_doc.get("outstanding_amount")
bill_no = ref_doc.get("bill_no")
elif reference_doctype == "Expense Claim": elif reference_doctype == "Expense Claim":
outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \ outstanding_amount = flt(ref_doc.get("total_sanctioned_amount")) \
- flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount")) - flt(ref_doc.get("total_amount+reimbursed")) - flt(ref_doc.get("total_advance_amount"))
@@ -799,7 +804,8 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
"due_date": ref_doc.get("due_date"), "due_date": ref_doc.get("due_date"),
"total_amount": total_amount, "total_amount": total_amount,
"outstanding_amount": outstanding_amount, "outstanding_amount": outstanding_amount,
"exchange_rate": exchange_rate "exchange_rate": exchange_rate,
"bill_no": bill_no
}) })

View File

@@ -468,7 +468,7 @@ cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(
cur_frm.cscript.cost_center = function(doc, cdt, cdn){ cur_frm.cscript.cost_center = function(doc, cdt, cdn){
var d = locals[cdt][cdn]; var d = locals[cdt][cdn];
if(d.idx == 1 && d.cost_center){ if(d.cost_center){
var cl = doc.items || []; var cl = doc.items || [];
for(var i = 0; i < cl.length; i++){ for(var i = 0; i < cl.length; i++){
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center; if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;

View File

@@ -344,6 +344,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])
pi.disable_rounded_total = 1 pi.disable_rounded_total = 1
pi.allocate_advances_automatically = 0
pi.append("advances", { pi.append("advances", {
"reference_type": "Journal Entry", "reference_type": "Journal Entry",
"reference_name": jv.name, "reference_name": jv.name,
@@ -383,6 +384,7 @@ class TestPurchaseInvoice(unittest.TestCase):
pi = frappe.copy_doc(test_records[0]) pi = frappe.copy_doc(test_records[0])
pi.disable_rounded_total = 1 pi.disable_rounded_total = 1
pi.allocate_advances_automatically = 0
pi.append("advances", { pi.append("advances", {
"reference_type": "Journal Entry", "reference_type": "Journal Entry",
"reference_name": jv.name, "reference_name": jv.name,

File diff suppressed because it is too large Load Diff

View File

@@ -855,6 +855,7 @@ class TestSalesInvoice(unittest.TestCase):
jv.submit() jv.submit()
si = frappe.copy_doc(test_records[0]) si = frappe.copy_doc(test_records[0])
si.allocate_advances_automatically = 0
si.append("advances", { si.append("advances", {
"doctype": "Sales Invoice Advance", "doctype": "Sales Invoice Advance",
"reference_type": "Journal Entry", "reference_type": "Journal Entry",
@@ -1361,7 +1362,7 @@ class TestSalesInvoice(unittest.TestCase):
"included_in_print_rate": 1 "included_in_print_rate": 1
}) })
si.save() si.save()
si.submit()
self.assertEqual(si.net_total, 19453.13) self.assertEqual(si.net_total, 19453.13)
self.assertEqual(si.grand_total, 24900) self.assertEqual(si.grand_total, 24900)
self.assertEqual(si.total_taxes_and_charges, 5446.88) self.assertEqual(si.total_taxes_and_charges, 5446.88)
@@ -1383,6 +1384,50 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][1], gle.debit) self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit) self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_rounding_adjustment_2(self):
si = create_sales_invoice(rate=400, do_not_save=True)
for rate in [400, 600, 100]:
si.append("items", {
"item_code": "_Test Item",
"gst_hsn_code": "999800",
"warehouse": "_Test Warehouse - _TC",
"qty": 1,
"rate": rate,
"income_account": "Sales - _TC",
"cost_center": "_Test Cost Center - _TC"
})
for tax_account in ["_Test Account VAT - _TC", "_Test Account Service Tax - _TC"]:
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": tax_account,
"description": tax_account,
"rate": 9,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1
})
si.save()
si.submit()
self.assertEqual(si.net_total, 1271.19)
self.assertEqual(si.grand_total, 1500)
self.assertEqual(si.total_taxes_and_charges, 228.82)
self.assertEqual(si.rounding_adjustment, -0.01)
expected_values = dict((d[0], d) for d in [
[si.debit_to, 1500, 0.0],
["_Test Account Service Tax - _TC", 0.0, 114.41],
["_Test Account VAT - _TC", 0.0, 114.41],
["Sales - _TC", 0.0, 1271.18]
])
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.name, as_dict=1)
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.account)
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_sales_invoice_with_shipping_rule(self): def test_sales_invoice_with_shipping_rule(self):
from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \ from erpnext.accounts.doctype.shipping_rule.test_shipping_rule \
import create_shipping_rule import create_shipping_rule

View File

@@ -135,9 +135,9 @@ def round_off_debit_credit(gl_map):
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff)) .format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
elif abs(debit_credit_diff) >= (1.0 / (10**precision)): elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
make_round_off_gle(gl_map, debit_credit_diff) make_round_off_gle(gl_map, debit_credit_diff, precision)
def make_round_off_gle(gl_map, debit_credit_diff): def make_round_off_gle(gl_map, debit_credit_diff, precision):
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company) round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company)
round_off_account_exists = False round_off_account_exists = False
round_off_gle = frappe._dict() round_off_gle = frappe._dict()
@@ -150,6 +150,10 @@ def make_round_off_gle(gl_map, debit_credit_diff):
debit_credit_diff += flt(d.credit_in_account_currency) debit_credit_diff += flt(d.credit_in_account_currency)
round_off_account_exists = True round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
gl_map.remove(round_off_gle)
return
if not round_off_gle: if not round_off_gle:
for k in ["voucher_type", "voucher_no", "company", for k in ["voucher_type", "voucher_no", "company",
"posting_date", "remarks", "is_opening"]: "posting_date", "remarks", "is_opening"]:

View File

@@ -6,17 +6,18 @@
</style> </style>
<div class="page-break"> <div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading") {%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Payment Entry")) -%}{%- endif -%} and doc.set("select_print_heading", _("Payment Entry")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }} {{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom"> <div class="row margin-bottom">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr> <tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr> <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
</table> </table>
@@ -30,53 +31,46 @@
<th>Party</th> <th>Party</th>
<th>Amount</th> <th>Amount</th>
</tr> </tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% for entries in gl %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
</tr>
<tr> <tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td> <td class="top-bottom" colspan="5"><strong>Credit</strong></td>
</tr> </tr>
{% set total_credit = 0 -%} {% for entries in gl %}
{% for entries in doc.gl_entries %}
{% if entries.debit == 0.0 %} {% if entries.debit == 0.0 %}
<tr> <tr>
<td class="right top-bottom">{{ entries.account }}</td> <td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td> <td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td> <td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.credit }}</td> <td class="left top-bottom">{{ entries.credit }}</td>
{% set total_credit = total_credit + entries.credit -%}
</tr> </tr>
<tr> <tr>
<td class="top-bottom" colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td> <td class="top-bottom" colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr> </tr>
{% endif %}
{% endfor %}
<tr> <tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td> <td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{total_credit}}</td> <td class="left" >{{ gl | sum(attribute='credit') }}</td>
</tr> </tr>
{% endif %}
{% endfor %}
<tr>
<td class="top-bottom" colspan="4"> </td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% set total_debit = 0 -%}
{% for entries in doc.gl_entries %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
{% set total_debit = total_debit + entries.debit -%}
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="top-bottom"colspan="4"><strong> Narration </strong><br>{{ entries.remarks }}</td>
</tr>
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{total_debit}}</td>
</tr>
{% endif %}
{% endfor %}
</table> </table>
<div> <div>
</div> </div>

View File

@@ -3,26 +3,25 @@
.table-bordered td.top-bottom {border-top: none !important;border-bottom: none !important;} .table-bordered td.top-bottom {border-top: none !important;border-bottom: none !important;}
.table-bordered td.right{border-right: none !important;} .table-bordered td.right{border-right: none !important;}
.table-bordered td.left{border-left: none !important;} .table-bordered td.left{border-left: none !important;}
</style> </style>
<div class="page-break"> <div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading") {%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Journal Entry")) -%}{%- endif -%} and doc.set("select_print_heading", _("Journal Entry")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }} {{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom"> <div class="row">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr> <tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr> <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
</table> </table>
</div> </div>
</div> </div>
<div class="margin-top"> <div>
<table class="table table-bordered table-condensed"> <table class="table table-bordered table-condensed">
<tr> <tr>
<th>Account</th> <th>Account</th>
@@ -30,47 +29,43 @@
<th>Party</th> <th>Party</th>
<th>Amount</th> <th>Amount</th>
</tr> </tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td>
</tr>
{% for entries in gl %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{ gl | sum(attribute='debit') }}</td>
</tr>
<tr> <tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td> <td class="top-bottom" colspan="5"><strong>Credit</strong></td>
</tr> </tr>
{% set total_credit = 0 -%} {% for entries in gl %}
{% for entries in doc.gl_entries %}
{% if entries.debit == 0.0 %} {% if entries.debit == 0.0 %}
<tr> <tr>
<td class="right top-bottom">{{ entries.account }}</td> <td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td> <td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td> <td class="right left top-bottom">{{ entries.party }}</td>
<td class="left top-bottom">{{ entries.credit }}</td> <td class="left top-bottom">{{ entries.credit }}</td>
{% set total_credit = total_credit + entries.credit -%}
</tr>
<tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{total_credit}}</td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<tr> <tr>
<td class="top-bottom" colspan="4"> </td> <td class="right" colspan="3"><strong>Total (credit) </strong></td>
<td class="left" >{{ gl | sum(attribute='credit') }}</td>
</tr> </tr>
<tr> <tr>
<td class="top-bottom" colspan="5"><strong>Debit</strong></td> <td class="top-bottom" colspan="5"><b>Narration: </b>{{ gl[0].remarks }}</td>
</tr> </tr>
{% set total_debit = 0 -%}
{% for entries in doc.gl_entries %}
{% if entries.credit == 0.0 %}
<tr>
<td class="right top-bottom">{{ entries.account }}</td>
<td class="right left top-bottom">{{ entries.party_type }}</td>
<td class="right left top-bottom">{{ entries.party }}</td>
{% set total_debit = total_debit + entries.debit -%}
<td class="left top-bottom">{{ entries.debit }}</td>
</tr>
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
<td class="left" >{{total_debit}}</td>
</tr>
{% endif %}
{% endfor %}
</table> </table>
<div> <div>
</div> </div>

View File

@@ -1,10 +1,11 @@
{%- from "templates/print_formats/standard_macros.html" import add_header -%} {%- from "templates/print_formats/standard_macros.html" import add_header -%}
<div class="page-break"> <div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading") {%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Purchase Invoice")) -%}{%- endif -%} and doc.set("select_print_heading", _("Purchase Invoice")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }} {{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom"> <div class="row margin-bottom">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr> <tr><td><strong>Supplier Name: </strong></td><td>{{ doc.supplier }}</td></tr>
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr> <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
@@ -13,7 +14,7 @@
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr> <tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr> <tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr> <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
@@ -49,21 +50,27 @@
</table> </table>
</div> </div>
<div class="row margin-bottom"> <div class="row margin-bottom">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr> <tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr> <tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr> <tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr> <tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
{% for tax in doc.taxes %} {% for tax in doc.taxes %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr> {% if tax.tax_amount_after_discount_amount!= 0 %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% endif %}
{% endfor %} {% endfor %}
{% if doc.taxes_and_charges_added!= 0 %}
<tr><td><strong> Taxes and Charges Added: </strong></td><td>{{ doc.taxes_and_charges_added }}</td></tr> <tr><td><strong> Taxes and Charges Added: </strong></td><td>{{ doc.taxes_and_charges_added }}</td></tr>
{% endif %}
{% if doc.taxes_and_charges_deducted!= 0 %}
<tr><td><strong> Taxes and Charges Deducted: </strong></td><td>{{ doc.taxes_and_charges_deducted }}</td></tr> <tr><td><strong> Taxes and Charges Deducted: </strong></td><td>{{ doc.taxes_and_charges_deducted }}</td></tr>
{% endif %}
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr> <tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr> <tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
</table> </table>
@@ -76,17 +83,17 @@
<th>Account</th> <th>Account</th>
<th>Party Type</th> <th>Party Type</th>
<th>Party</th> <th>Party</th>
<th>Credit Amount</th>
<th>Debit Amount</th> <th>Debit Amount</th>
<th>Credit Amount</th>
</tr> </tr>
{% for entries in doc.gl_entries %} {% for entries in gl %}
<tr> <tr>
<td>{{ loop.index }}</td> <td>{{ loop.index }}</td>
<td>{{ entries.account }}</td> <td>{{ entries.account }}</td>
<td>{{ entries.party_type }}</td> <td>{{ entries.party_type }}</td>
<td>{{ entries.party }}</td> <td>{{ entries.party }}</td>
<td>{{ entries.credit }}</td>
<td>{{ entries.debit }}</td> <td>{{ entries.debit }}</td>
<td>{{ entries.credit }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr> <tr>

View File

@@ -1,10 +1,11 @@
{%- from "templates/print_formats/standard_macros.html" import add_header -%} {%- from "templates/print_formats/standard_macros.html" import add_header -%}
<div class="page-break"> <div>
{% set gl = frappe.get_list(doctype="GL Entry", fields=["account", "party_type", "party", "debit", "credit", "remarks"], filters={"voucher_type": doc.doctype, "voucher_no": doc.name}) %}
{%- if not doc.get("print_heading") and not doc.get("select_print_heading") {%- if not doc.get("print_heading") and not doc.get("select_print_heading")
and doc.set("select_print_heading", _("Sales Invoice")) -%}{%- endif -%} and doc.set("select_print_heading", _("Sales Invoice")) -%}{%- endif -%}
{{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }} {{ add_header(0, 1, doc, letter_head, no_letterhead, print_settings) }}
<div class="row margin-bottom"> <div class="row margin-bottom">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr> <tr><td><strong>Customer Name: </strong></td><td>{{ doc.customer }}</td></tr>
<tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr> <tr><td><strong>Due Date: </strong></td><td>{{ frappe.utils.formatdate(doc.due_date) }}</td></tr>
@@ -13,7 +14,7 @@
<tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr> <tr><td><strong>Mobile no: </strong> </td><td>{{doc.contact_mobile}}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr> <tr><td><strong>Voucher No: </strong></td><td>{{ doc.name }}</td></tr>
<tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr> <tr><td><strong>Date: </strong></td><td>{{ frappe.utils.formatdate(doc.creation) }}</td></tr>
@@ -45,18 +46,20 @@
</table> </table>
</div> </div>
<div class="row margin-bottom"> <div class="row margin-bottom">
<div class="col-sm-6"> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr> <tr><td><strong>Total Quantity: </strong></td><td>{{ doc.total_qty }}</td></tr>
<tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr> <tr><td><strong>Total: </strong></td><td>{{doc.total}}</td></tr>
<tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr> <tr><td><strong>Net Weight: </strong></td><td>{{ doc.total_net_weight }}</td></tr>
</table> </table>
</div> </div>
<div> <div class="col-xs-6">
<table> <table>
<tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr> <tr><td><strong>Tax and Charges: </strong></td><td>{{doc.taxes_and_charges}}</td></tr>
{% for tax in doc.taxes %} {% for tax in doc.taxes %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr> {% if tax.tax_amount_after_discount_amount!= 0 %}
<tr><td><strong>{{ tax.account_head }}: </strong></td><td>{{ tax.tax_amount_after_discount_amount }}</td></tr>
{% endif %}
{% endfor %} {% endfor %}
<tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr> <tr><td><strong> Total Taxes and Charges: </strong></td><td>{{ doc.total_taxes_and_charges }}</td></tr>
<tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr> <tr><td><strong> Net Payable: </strong></td><td>{{ doc.grand_total }}</td></tr>
@@ -70,17 +73,17 @@
<th>Account</th> <th>Account</th>
<th>Party Type</th> <th>Party Type</th>
<th>Party</th> <th>Party</th>
<th>Credit Amount</th>
<th>Debit Amount</th> <th>Debit Amount</th>
<th>Credit Amount</th>
</tr> </tr>
{% for entries in doc.gl_entries %} {% for entries in gl %}
<tr> <tr>
<td>{{ loop.index }}</td> <td>{{ loop.index }}</td>
<td>{{ entries.account }}</td> <td>{{ entries.account }}</td>
<td>{{ entries.party_type }}</td> <td>{{ entries.party_type }}</td>
<td>{{ entries.party }}</td> <td>{{ entries.party }}</td>
<td>{{ entries.credit }}</td>
<td>{{ entries.debit }}</td> <td>{{ entries.debit }}</td>
<td>{{ entries.credit }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr> <tr>

View File

@@ -107,26 +107,28 @@
<thead> <thead>
<tr> <tr>
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %} {% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
<th style="width: 7%">{%= __("Date") %}</th> <th style="width: 9%">{%= __("Date") %}</th>
<th style="width: 7%">{%= __("Age (Days)") %}</th> <th style="width: 5%">{%= __("Age (Days)") %}</th>
<th style="width: 13%">{%= __("Reference") %}</th>
{% if(report.report_name === "Accounts Receivable") { %} {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
<th style="width: 10%">{%= __("Sales Person") %}</th> <th style="width: 16%">{%= __("Reference") %}</th>
<th style="width: 10%">{%= __("Sales Person") %}</th>
{% } else { %}
<th style="width: 26%">{%= __("Reference") %}</th>
{% } %} {% } %}
{% if(!filters.show_pdc_in_print) { %} {% if(!filters.show_pdc_in_print) { %}
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th> <th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
{% } %} {% } %}
<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th> <th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
{% if(!filters.show_pdc_in_print) { %} {% if(!filters.show_pdc_in_print) { %}
<th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th> <th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
<th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th> <th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
{% } %} {% } %}
<th style="width: 15%; text-align: right">{%= __("Outstanding Amount") %}</th> <th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
{% if(filters.show_pdc_in_print) { %} {% if(filters.show_pdc_in_print) { %}
{% if(report.report_name === "Accounts Receivable") { %} {% if(report.report_name === "Accounts Receivable") { %}
<th style="width: 10%">{%= __("Customer LPO No.") %}</th> <th style="width: 10%">{%= __("Customer LPO No.") %}</th>
{% } %} {% } %}
<th style="width: 10%">{%= __("PDC/LC Date") %}</th>
<th style="width: 10%">{%= __("PDC/LC Ref") %}</th> <th style="width: 10%">{%= __("PDC/LC Ref") %}</th>
<th style="width: 10%">{%= __("PDC/LC Amount") %}</th> <th style="width: 10%">{%= __("PDC/LC Amount") %}</th>
<th style="width: 10%">{%= __("Remaining Balance") %}</th> <th style="width: 10%">{%= __("Remaining Balance") %}</th>
@@ -155,7 +157,7 @@
{%= data[i]["voucher_no"] %} {%= data[i]["voucher_no"] %}
</td> </td>
{% if(report.report_name === "Accounts Receivable") { %} {% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
<td>{%= data[i]["sales_person"] %}</td> <td>{%= data[i]["sales_person"] %}</td>
{% } %} {% } %}
@@ -195,7 +197,6 @@
<td style="text-align: right"> <td style="text-align: right">
{%= data[i]["po_no"] %}</td> {%= data[i]["po_no"] %}</td>
{% } %} {% } %}
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][("pdc/lc_date")]) %}</td>
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td> <td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td> <td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td> <td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>
@@ -226,7 +227,6 @@
<td style="text-align: right"> <td style="text-align: right">
{%= data[i][__("Customer LPO")] %}</td> {%= data[i][__("Customer LPO")] %}</td>
{% } %} {% } %}
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
<td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td> <td style="text-align: right">{%= data[i][("pdc/lc_ref")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td> <td style="text-align: right">{%= format_currency(data[i][("pdc/lc_amount")], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td> <td style="text-align: right">{%= format_currency(data[i][("remaining_balance")], data[i]["currency"]) %}</td>

View File

@@ -102,14 +102,19 @@ frappe.query_reports["Accounts Receivable"] = {
"fieldtype": "Link", "fieldtype": "Link",
"options": "Sales Person" "options": "Sales Person"
}, },
{
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldtype": "Check",
},
{ {
"fieldname":"show_pdc_in_print", "fieldname":"show_pdc_in_print",
"label": __("Show PDC in Print"), "label": __("Show PDC in Print"),
"fieldtype": "Check", "fieldtype": "Check",
}, },
{ {
"fieldname":"based_on_payment_terms", "fieldname":"show_sales_person_in_print",
"label": __("Based On Payment Terms"), "label": __("Show Sales Person in Print"),
"fieldtype": "Check", "fieldtype": "Check",
}, },
{ {

View File

@@ -194,10 +194,9 @@ class ReceivablePayableReport(object):
self.payment_term_map = self.get_payment_term_detail(voucher_nos) self.payment_term_map = self.get_payment_term_detail(voucher_nos)
for gle in gl_entries_data: for gle in gl_entries_data:
if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
gle,self.filters.report_date, self.dr_or_cr, return_entries) gle,self.filters.report_date, self.dr_or_cr, return_entries)
temp_outstanding_amt = outstanding_amount temp_outstanding_amt = outstanding_amount
temp_credit_note_amt = credit_note_amount temp_credit_note_amt = credit_note_amount
@@ -377,7 +376,7 @@ class ReceivablePayableReport(object):
# returns a generator # returns a generator
return self.get_gl_entries(party_type, report_date) return self.get_gl_entries(party_type, report_date)
def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers): def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
return ( return (
# advance # advance
(not gle.against_voucher) or (not gle.against_voucher) or
@@ -388,30 +387,37 @@ class ReceivablePayableReport(object):
# sales invoice/purchase invoice # sales invoice/purchase invoice
(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or (gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
# standalone credit notes
(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
# entries adjusted with future vouchers # entries adjusted with future vouchers
((gle.against_voucher_type, gle.against_voucher) in future_vouchers) ((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
) )
def get_return_entries(self, party_type): def get_return_entries(self, party_type):
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})] return_entries = frappe._dict(frappe.get_all(doctype,
filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
return return_entries
def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries): def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
payment_amount, credit_note_amount = 0.0, 0.0 payment_amount, credit_note_amount = 0.0, 0.0
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit" reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no): for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name: if getdate(e.posting_date) <= report_date \
and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision) amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
if e.voucher_no not in return_entries: if e.voucher_no not in return_entries:
payment_amount += amount payment_amount += amount
else: else:
credit_note_amount += amount credit_note_amount += amount
outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision) voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
- flt(gle.get(reverse_dr_or_cr), self.currency_precision) if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
- payment_amount - credit_note_amount), self.currency_precision)) voucher_amount = 0
outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
credit_note_amount = flt(credit_note_amount, self.currency_precision) credit_note_amount = flt(credit_note_amount, self.currency_precision)
return outstanding_amount, credit_note_amount, payment_amount return outstanding_amount, credit_note_amount, payment_amount

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
import erpnext import erpnext
from frappe import _ from frappe import _, scrub
from frappe.utils import getdate, nowdate from frappe.utils import getdate, nowdate
from six import iteritems, itervalues from six import iteritems, itervalues
@@ -14,6 +14,9 @@ class PartyLedgerSummaryReport(object):
self.filters.from_date = getdate(self.filters.from_date or nowdate()) self.filters.from_date = getdate(self.filters.from_date or nowdate())
self.filters.to_date = getdate(self.filters.to_date or nowdate()) self.filters.to_date = getdate(self.filters.to_date or nowdate())
if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
def run(self, args): def run(self, args):
if self.filters.from_date > self.filters.to_date: if self.filters.from_date > self.filters.to_date:
frappe.throw(_("From Date must be before To Date")) frappe.throw(_("From Date must be before To Date"))
@@ -21,10 +24,9 @@ class PartyLedgerSummaryReport(object):
self.filters.party_type = args.get("party_type") self.filters.party_type = args.get("party_type")
self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1]) self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \ self.get_gl_entries()
else "discount_received_account" self.get_return_invoices()
self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company', self.get_party_adjustment_amounts()
self.filters.company, ["round_off_account", "write_off_account", discount_account_field])
columns = self.get_columns() columns = self.get_columns()
data = self.get_data() data = self.get_data()
@@ -48,7 +50,6 @@ class PartyLedgerSummaryReport(object):
}) })
credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note"
discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received"
columns += [ columns += [
{ {
@@ -79,27 +80,19 @@ class PartyLedgerSummaryReport(object):
"options": "currency", "options": "currency",
"width": 120 "width": 120
}, },
{ ]
"label": _(discount_allowed_or_received),
"fieldname": "discount_amount", for account in self.party_adjustment_accounts:
columns.append({
"label": account,
"fieldname": "adj_" + scrub(account),
"fieldtype": "Currency", "fieldtype": "Currency",
"options": "currency", "options": "currency",
"width": 120 "width": 120,
}, "is_adjustment": 1
{ })
"label": _("Write Off Amount"),
"fieldname": "write_off_amount", columns += [
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
{
"label": _("Other Adjustments"),
"fieldname": "adjustment_amount",
"fieldtype": "Currency",
"options": "currency",
"width": 120
},
{ {
"label": _("Closing Balance"), "label": _("Closing Balance"),
"fieldname": "closing_balance", "fieldname": "closing_balance",
@@ -119,17 +112,10 @@ class PartyLedgerSummaryReport(object):
return columns return columns
def get_data(self): def get_data(self):
if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
self.get_gl_entries()
self.get_return_invoices()
self.get_party_adjustment_amounts()
self.party_data = frappe._dict({}) self.party_data = frappe._dict({})
for gle in self.gl_entries: for gle in self.gl_entries:
self.party_data.setdefault(gle.party, frappe._dict({ self.party_data.setdefault(gle.party, frappe._dict({
@@ -146,7 +132,7 @@ class PartyLedgerSummaryReport(object):
amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) amount = gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
self.party_data[gle.party].closing_balance += amount self.party_data[gle.party].closing_balance += amount
if gle.posting_date < self.filters.from_date: if gle.posting_date < self.filters.from_date or gle.is_opening == "Yes":
self.party_data[gle.party].opening_balance += amount self.party_data[gle.party].opening_balance += amount
else: else:
if amount > 0: if amount > 0:
@@ -161,9 +147,10 @@ class PartyLedgerSummaryReport(object):
if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount: if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount:
total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))]) total_party_adjustment = sum([amount for amount in itervalues(self.party_adjustment_details.get(party, {}))])
row.paid_amount -= total_party_adjustment row.paid_amount -= total_party_adjustment
row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0)
row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0) adjustments = self.party_adjustment_details.get(party, {})
row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount for account in self.party_adjustment_accounts:
row["adj_" + scrub(account)] = adjustments.get(account, 0)
out.append(row) out.append(row)
@@ -182,7 +169,7 @@ class PartyLedgerSummaryReport(object):
self.gl_entries = frappe.db.sql(""" self.gl_entries = frappe.db.sql("""
select select
gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type, gle.posting_date, gle.party, gle.voucher_type, gle.voucher_no, gle.against_voucher_type,
gle.against_voucher, gle.debit, gle.credit {join_field} gle.against_voucher, gle.debit, gle.credit, gle.is_opening {join_field}
from `tabGL Entry` gle from `tabGL Entry` gle
{join} {join}
where where
@@ -254,9 +241,10 @@ class PartyLedgerSummaryReport(object):
def get_party_adjustment_amounts(self): def get_party_adjustment_amounts(self):
conditions = self.prepare_conditions() conditions = self.prepare_conditions()
income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income" income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account"
invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit"
round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account")
gl_entries = frappe.db.sql(""" gl_entries = frappe.db.sql("""
select select
@@ -267,7 +255,7 @@ class PartyLedgerSummaryReport(object):
docstatus < 2 docstatus < 2
and (voucher_type, voucher_no) in ( and (voucher_type, voucher_no) in (
select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
where acc.name = gle.account and acc.root_type = '{income_or_expense}' where acc.name = gle.account and acc.account_type = '{income_or_expense}'
and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2
) and (voucher_type, voucher_no) in ( ) and (voucher_type, voucher_no) in (
select voucher_type, voucher_no from `tabGL Entry` gle select voucher_type, voucher_no from `tabGL Entry` gle
@@ -277,6 +265,7 @@ class PartyLedgerSummaryReport(object):
""".format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True)
self.party_adjustment_details = {} self.party_adjustment_details = {}
self.party_adjustment_accounts = set()
adjustment_voucher_entries = {} adjustment_voucher_entries = {}
for gle in gl_entries: for gle in gl_entries:
adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), [])
@@ -288,12 +277,12 @@ class PartyLedgerSummaryReport(object):
has_irrelevant_entry = False has_irrelevant_entry = False
for gle in voucher_gl_entries: for gle in voucher_gl_entries:
if gle.account == self.round_off_account: if gle.account == round_off_account:
continue continue
elif gle.party: elif gle.party:
parties.setdefault(gle.party, 0) parties.setdefault(gle.party, 0)
parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr) parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr)
elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense: elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense:
accounts.setdefault(gle.account, 0) accounts.setdefault(gle.account, 0)
accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr)
else: else:
@@ -303,11 +292,13 @@ class PartyLedgerSummaryReport(object):
if len(parties) == 1: if len(parties) == 1:
party = parties.keys()[0] party = parties.keys()[0]
for account, amount in iteritems(accounts): for account, amount in iteritems(accounts):
self.party_adjustment_accounts.add(account)
self.party_adjustment_details.setdefault(party, {}) self.party_adjustment_details.setdefault(party, {})
self.party_adjustment_details[party].setdefault(account, 0) self.party_adjustment_details[party].setdefault(account, 0)
self.party_adjustment_details[party][account] += amount self.party_adjustment_details[party][account] += amount
elif len(accounts) == 1 and not has_irrelevant_entry: elif len(accounts) == 1 and not has_irrelevant_entry:
account = accounts.keys()[0] account = accounts.keys()[0]
self.party_adjustment_accounts.add(account)
for party, amount in iteritems(parties): for party, amount in iteritems(parties):
self.party_adjustment_details.setdefault(party, {}) self.party_adjustment_details.setdefault(party, {})
self.party_adjustment_details[party].setdefault(account, 0) self.party_adjustment_details[party].setdefault(account, 0)

View File

@@ -54,8 +54,10 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom
] ]
row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount] \ if d.stock_uom != d.uom and d.stock_qty:
if d.stock_uom != d.uom and d.stock_qty != 0 else [d.base_net_rate, d.base_net_amount] row += [(d.base_net_rate * d.qty)/d.stock_qty, d.base_net_amount]
else:
row += [d.base_net_rate, d.base_net_amount]
total_tax = 0 total_tax = 0
for tax in tax_columns: for tax in tax_columns:

View File

@@ -55,12 +55,15 @@ def get_result(filters):
supplier = supplier_map[d] supplier = supplier_map[d]
tds_doc = tds_docs[supplier.tax_withholding_category] tds_doc = tds_docs[supplier.tax_withholding_category]
account = [i.account for i in tds_doc.accounts if i.company == filters.company][0] account_list = [i.account for i in tds_doc.accounts if i.company == filters.company]
if account_list:
account = account_list[0]
for k in gle_map[d]: for k in gle_map[d]:
if k.party == supplier_map[d] and k.credit > 0: if k.party == supplier_map[d] and k.credit > 0:
total_amount_credited += k.credit total_amount_credited += k.credit
elif k.account == account and k.credit > 0: elif account_list and k.account == account and k.credit > 0:
tds_deducted = k.credit tds_deducted = k.credit
total_amount_credited += k.credit total_amount_credited += k.credit

View File

@@ -206,12 +206,10 @@ frappe.ui.form.on('Asset', {
erpnext.asset.set_accululated_depreciation(frm); erpnext.asset.set_accululated_depreciation(frm);
}, },
depreciation_method: function(frm) {
frm.events.make_schedules_editable(frm);
},
make_schedules_editable: function(frm) { make_schedules_editable: function(frm) {
var is_editable = frm.doc.depreciation_method==="Manual" ? true : false; var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
? true : false;
frm.toggle_enable("schedules", is_editable); frm.toggle_enable("schedules", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable); frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable); frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
@@ -296,6 +294,44 @@ frappe.ui.form.on('Asset', {
}) })
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation); frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
},
set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
frappe.call({
method: "get_depreciation_rate",
doc: frm.doc,
args: row,
callback: function(r) {
if (r.message) {
frappe.model.set_value(row.doctype, row.name, "rate_of_depreciation", r.message);
}
}
});
}
}
});
frappe.ui.form.on('Asset Finance Book', {
depreciation_method: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
frm.events.make_schedules_editable(frm);
},
expected_value_after_useful_life: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
frequency_of_depreciation: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
},
total_number_of_depreciations: function(frm, cdt, cdn) {
const row = locals[cdt][cdn];
frm.events.set_depreciation_rate(frm, row);
} }
}); });

View File

@@ -3,8 +3,9 @@
# For license information, please see license.txt # For license information, please see license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext, math, json
from frappe import _ from frappe import _
from six import string_types
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
from frappe.model.document import Document from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
@@ -20,6 +21,7 @@ class Asset(AccountsController):
self.validate_item() self.validate_item()
self.set_missing_values() self.set_missing_values()
if self.calculate_depreciation: if self.calculate_depreciation:
self.set_depreciation_rate()
self.make_depreciation_schedule() self.make_depreciation_schedule()
self.set_accumulated_depreciation() self.set_accumulated_depreciation()
else: else:
@@ -89,17 +91,22 @@ class Asset(AccountsController):
if self.is_existing_asset: if self.is_existing_asset:
return return
date = nowdate()
docname = self.purchase_receipt or self.purchase_invoice docname = self.purchase_receipt or self.purchase_invoice
if docname: if docname:
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
date = frappe.db.get_value(doctype, docname, 'posting_date') date = frappe.db.get_value(doctype, docname, 'posting_date')
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(date): if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date")) frappe.throw(_("Available-for-use Date should be after purchase date"))
def set_depreciation_rate(self):
for d in self.get("finance_books"):
d.rate_of_depreciation = self.get_depreciation_rate(d)
def make_depreciation_schedule(self): def make_depreciation_schedule(self):
if self.depreciation_method != 'Manual': depreciation_method = [d.depreciation_method for d in self.finance_books]
if 'Manual' not in depreciation_method:
self.schedules = [] self.schedules = []
if not self.get("schedules") and self.available_for_use_date: if not self.get("schedules") and self.available_for_use_date:
@@ -254,14 +261,16 @@ class Asset(AccountsController):
return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation) return flt(self.get('finance_books')[cint(idx)-1].value_after_depreciation)
def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row): def get_depreciation_amount(self, depreciable_value, total_number_of_depreciations, row):
percentage_value = 100.0 if row.depreciation_method == 'Written Down Value' else 200.0 if row.depreciation_method in ["Straight Line", "Manual"]:
amt = (flt(self.gross_purchase_amount) - flt(row.expected_value_after_useful_life) -
flt(self.opening_accumulated_depreciation))
factor = percentage_value / cint(total_number_of_depreciations) depreciation_amount = amt * row.rate_of_depreciation
depreciation_amount = flt(depreciable_value * factor / 100, 0) else:
depreciation_amount = flt(depreciable_value) * (flt(row.rate_of_depreciation) / 100)
value_after_depreciation = flt(depreciable_value) - depreciation_amount value_after_depreciation = flt(depreciable_value) - depreciation_amount
if value_after_depreciation < flt(row.expected_value_after_useful_life): if value_after_depreciation < flt(row.expected_value_after_useful_life):
depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life) depreciation_amount = flt(depreciable_value) - flt(row.expected_value_after_useful_life)
return depreciation_amount return depreciation_amount
@@ -394,6 +403,32 @@ class Asset(AccountsController):
make_gl_entries(gl_entries) make_gl_entries(gl_entries)
self.db_set('booked_fixed_asset', 1) self.db_set('booked_fixed_asset', 1)
def get_depreciation_rate(self, args):
if isinstance(args, string_types):
args = json.loads(args)
number_of_depreciations_booked = 0
if self.is_existing_asset:
number_of_depreciations_booked = self.number_of_depreciations_booked
float_precision = cint(frappe.db.get_default("float_precision")) or 2
tot_no_of_depreciation = flt(args.get("total_number_of_depreciations")) - flt(number_of_depreciations_booked)
if args.get("depreciation_method") in ["Straight Line", "Manual"]:
return 1.0 / tot_no_of_depreciation
if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations")
if args.get("depreciation_method") == "Written Down Value" and not args.get("rate_of_depreciation"):
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
# square root of flt(salvage_value) / flt(asset_cost)
depreciation_rate = math.pow(value, 1.0/flt(no_of_years, 2))
return 100 * (1 - flt(depreciation_rate, float_precision))
def update_maintenance_status(): def update_maintenance_status():
assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1}) assets = frappe.get_all('Asset', filters = {'docstatus': 1, 'maintenance_required': 1})
@@ -480,7 +515,6 @@ def create_asset_adjustment(asset, asset_category, company):
@frappe.whitelist() @frappe.whitelist()
def transfer_asset(args): def transfer_asset(args):
import json
args = json.loads(args) args = json.loads(args)
if args.get('serial_no'): if args.get('serial_no'):

View File

@@ -160,9 +160,9 @@ class TestAsset(unittest.TestCase):
asset.save() asset.save()
expected_schedules = [ expected_schedules = [
["2020-06-06", 66667.0, 66667.0], ["2020-06-06", 66666.67, 66666.67],
["2021-04-06", 22222.0, 88889.0], ["2021-04-06", 22222.22, 88888.89],
["2022-02-06", 1111.0, 90000.0] ["2022-02-06", 1111.11, 90000.0]
] ]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -192,8 +192,8 @@ class TestAsset(unittest.TestCase):
asset.save() asset.save()
expected_schedules = [ expected_schedules = [
["2020-06-06", 33333.0, 83333.0], ["2020-06-06", 33333.33, 83333.33],
["2021-04-06", 6667.0, 90000.0] ["2021-04-06", 6666.67, 90000.0]
] ]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -209,7 +209,7 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name) asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1 asset.calculate_depreciation = 1
asset.purchase_date = '2020-06-06' asset.purchase_date = '2020-01-30'
asset.is_existing_asset = 0 asset.is_existing_asset = 0
asset.available_for_use_date = "2020-01-30" asset.available_for_use_date = "2020-01-30"
asset.append("finance_books", { asset.append("finance_books", {
@@ -244,7 +244,7 @@ class TestAsset(unittest.TestCase):
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name) asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1 asset.calculate_depreciation = 1
asset.purchase_date = '2020-06-06' asset.purchase_date = '2020-01-30'
asset.available_for_use_date = "2020-01-30" asset.available_for_use_date = "2020-01-30"
asset.append("finance_books", { asset.append("finance_books", {
"expected_value_after_useful_life": 10000, "expected_value_after_useful_life": 10000,
@@ -277,6 +277,37 @@ class TestAsset(unittest.TestCase):
self.assertEqual(gle, expected_gle) self.assertEqual(gle, expected_gle)
self.assertEqual(asset.get("value_after_depreciation"), 0) self.assertEqual(asset.get("value_after_depreciation"), 0)
def test_depreciation_entry_for_wdv(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=8000.0, location="Test Location")
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
asset.calculate_depreciation = 1
asset.available_for_use_date = '2030-06-06'
asset.purchase_date = '2030-06-06'
asset.append("finance_books", {
"expected_value_after_useful_life": 1000,
"depreciation_method": "Written Down Value",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 12,
"depreciation_start_date": "2030-12-31"
})
asset.save(ignore_permissions=True)
self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
expected_schedules = [
["2030-12-31", 4000.0, 4000.0],
["2031-12-31", 2000.0, 6000.0],
["2032-12-31", 1000.0, 7000.0],
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
for d in asset.get("schedules")]
self.assertEqual(schedules, expected_schedules)
def test_depreciation_entry_cancellation(self): def test_depreciation_entry_cancellation(self):
pr = make_purchase_receipt(item_code="Macbook Pro", pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=100000.0, location="Test Location") qty=1, rate=100000.0, location="Test Location")

View File

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@@ -14,11 +15,13 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "finance_book", "fieldname": "finance_book",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -42,14 +45,17 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "depreciation_method", "fieldname": "depreciation_method",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -73,14 +79,17 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_number_of_depreciations", "fieldname": "total_number_of_depreciations",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -103,14 +112,17 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_5", "fieldname": "column_break_5",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -133,14 +145,17 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "frequency_of_depreciation", "fieldname": "frequency_of_depreciation",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -163,15 +178,18 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:parent.doctype == 'Asset'", "depends_on": "eval:parent.doctype == 'Asset'",
"fetch_if_empty": 0,
"fieldname": "depreciation_start_date", "fieldname": "depreciation_start_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -194,16 +212,19 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "0", "default": "0",
"depends_on": "eval:parent.doctype == 'Asset'", "depends_on": "eval:parent.doctype == 'Asset'",
"fetch_if_empty": 0,
"fieldname": "expected_value_after_useful_life", "fieldname": "expected_value_after_useful_life",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -227,14 +248,17 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "value_after_depreciation", "fieldname": "value_after_depreciation",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 1, "hidden": 1,
@@ -258,20 +282,54 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 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:doc.depreciation_method == 'Written Down Value'",
"description": "In Percentage",
"fetch_if_empty": 0,
"fieldname": "rate_of_depreciation",
"fieldtype": "Percent",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate of Depreciation",
"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 "unique": 0
} }
], ],
"has_web_view": 0, "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 0, "idx": 0,
"image_view": 0,
"in_create": 0, "in_create": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-12 14:56:44.800046", "modified": "2019-04-09 19:45:14.523488",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset Finance Book", "name": "Asset Finance Book",
@@ -280,10 +338,10 @@
"permissions": [], "permissions": [],
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@@ -379,7 +379,9 @@ def make_purchase_invoice(source_name, target_doc=None):
def postprocess(source, target): def postprocess(source, target):
set_missing_values(source, target) set_missing_values(source, target)
#Get the advance paid Journal Entries in Purchase Invoice Advance #Get the advance paid Journal Entries in Purchase Invoice Advance
target.set_advances()
if target.get("allocate_advances_automatically"):
target.set_advances()
def update_item(obj, target, source_parent): def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt) target.amount = flt(obj.amount) - flt(obj.billed_amt)

View File

@@ -116,12 +116,6 @@ class AccountsController(TransactionBase):
self.validate_non_invoice_documents_schedule() self.validate_non_invoice_documents_schedule()
def before_print(self): def before_print(self):
if self.doctype in ['Journal Entry', 'Payment Entry', 'Sales Invoice', 'Purchase Invoice']:
self.gl_entries = frappe.get_list("GL Entry", filters={
"voucher_type": self.doctype,
"voucher_no": self.name
}, fields=["account", "party_type", "party", "debit", "credit", "remarks"])
if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice', if self.doctype in ['Purchase Order', 'Sales Order', 'Sales Invoice', 'Purchase Invoice',
'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']: 'Supplier Quotation', 'Purchase Receipt', 'Delivery Note', 'Quotation']:
if self.get("group_same_items"): if self.get("group_same_items"):

View File

@@ -2,8 +2,9 @@
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe, erpnext
from frappe import _ from frappe import _
from frappe.model.meta import get_field_precision
from frappe.utils import flt, get_datetime, format_datetime from frappe.utils import flt, get_datetime, format_datetime
class StockOverReturnError(frappe.ValidationError): pass class StockOverReturnError(frappe.ValidationError): pass
@@ -116,6 +117,10 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
already_returned_data = already_returned_items.get(args.item_code) or {} already_returned_data = already_returned_items.get(args.item_code) or {}
company_currency = erpnext.get_company_currency(doc.company)
stock_qty_precision = get_field_precision(frappe.get_meta(doc.doctype + " Item")
.get_field("stock_qty"), company_currency)
for column in fields: for column in fields:
returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0 returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
@@ -126,7 +131,7 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0) reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0)
current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0) current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0)
max_returnable_qty = flt(reference_qty) - returned_qty max_returnable_qty = flt(reference_qty, stock_qty_precision) - returned_qty
label = column.replace('_', ' ').title() label = column.replace('_', ' ').title()
if reference_qty: if reference_qty:
@@ -135,7 +140,7 @@ def validate_quantity(doc, args, ref, valid_items, already_returned_items):
elif returned_qty >= reference_qty and args.get(column): elif returned_qty >= reference_qty and args.get(column):
frappe.throw(_("Item {0} has already been returned") frappe.throw(_("Item {0} has already been returned")
.format(args.item_code), StockOverReturnError) .format(args.item_code), StockOverReturnError)
elif abs(current_stock_qty) > max_returnable_qty: elif abs(flt(current_stock_qty, stock_qty_precision)) > max_returnable_qty:
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}") frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
.format(args.idx, max_returnable_qty, args.item_code), StockOverReturnError) .format(args.idx, max_returnable_qty, args.item_code), StockOverReturnError)
@@ -239,6 +244,10 @@ def make_return_doc(doctype, source_name, target_doc=None):
doc.paid_amount = -1 * source.paid_amount doc.paid_amount = -1 * source.paid_amount
doc.base_paid_amount = -1 * source.base_paid_amount doc.base_paid_amount = -1 * source.base_paid_amount
if doc.get("is_return") and hasattr(doc, "packed_items"):
for d in doc.get("packed_items"):
d.qty = d.qty * -1
doc.discount_amount = -1 * source.discount_amount doc.discount_amount = -1 * source.discount_amount
doc.run_method("calculate_taxes_and_totals") doc.run_method("calculate_taxes_and_totals")

View File

@@ -42,10 +42,10 @@ def create_variant_with_tables(item, args):
return variant return variant
def make_item_variant(): def make_item_variant():
frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1) frappe.delete_doc_if_exists("Item", "_Test Variant Item-XSL", force=1)
variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Small"}') variant = create_variant_with_tables("_Test Variant Item", '{"Test Size": "Extra Small"}')
variant.item_code = "_Test Variant Item-S" variant.item_code = "_Test Variant Item-XSL"
variant.item_name = "_Test Variant Item-S" variant.item_name = "_Test Variant Item-XSL"
variant.save() variant.save()
return variant return variant

View File

@@ -162,6 +162,8 @@ def create_item_code(amazon_item_json, sku):
igroup.parent_item_group = mws_settings.item_group igroup.parent_item_group = mws_settings.item_group
igroup.insert() igroup.insert()
item.append("item_defaults", {'company':mws_settings.company})
item.insert(ignore_permissions=True) item.insert(ignore_permissions=True)
create_item_price(amazon_item_json, item.item_code) create_item_price(amazon_item_json, item.item_code)
@@ -213,7 +215,7 @@ def get_orders(after_date):
fulfillment_channels=["MFN", "AFN"], fulfillment_channels=["MFN", "AFN"],
lastupdatedafter=after_date, lastupdatedafter=after_date,
orderstatus=statuses, orderstatus=statuses,
max_results='20') max_results='50')
while True: while True:
orders_list = [] orders_list = []
@@ -432,8 +434,8 @@ def get_order_items(market_place_order_id):
return final_order_items return final_order_items
def get_item_code(order_item): def get_item_code(order_item):
asin = order_item.ASIN sku = order_item.SellerSKU
item_code = frappe.db.get_value("Item", {"amazon_item_code": asin}, "item_code") item_code = frappe.db.get_value("Item", {"item_code": sku}, "item_code")
if item_code: if item_code:
return item_code return item_code
@@ -451,11 +453,16 @@ def get_charges_and_fees(market_place_order_id):
shipment_item_list = return_as_list(shipment_event.ShipmentEvent.ShipmentItemList.ShipmentItem) shipment_item_list = return_as_list(shipment_event.ShipmentEvent.ShipmentItemList.ShipmentItem)
for shipment_item in shipment_item_list: for shipment_item in shipment_item_list:
charges = return_as_list(shipment_item.ItemChargeList.ChargeComponent) charges, fees = []
fees = return_as_list(shipment_item.ItemFeeList.FeeComponent)
if 'ItemChargeList' in shipment_item.keys():
charges = return_as_list(shipment_item.ItemChargeList.ChargeComponent)
if 'ItemFeeList' in shipment_item.keys():
fees = return_as_list(shipment_item.ItemFeeList.FeeComponent)
for charge in charges: for charge in charges:
if(charge.ChargeType != "Principal"): if(charge.ChargeType != "Principal") and float(charge.ChargeAmount.CurrencyAmount) != 0:
charge_account = get_account(charge.ChargeType) charge_account = get_account(charge.ChargeType)
charges_fees.get("charges").append({ charges_fees.get("charges").append({
"charge_type":"Actual", "charge_type":"Actual",
@@ -465,13 +472,14 @@ def get_charges_and_fees(market_place_order_id):
}) })
for fee in fees: for fee in fees:
fee_account = get_account(fee.FeeType) if float(fee.FeeAmount.CurrencyAmount) != 0:
charges_fees.get("fees").append({ fee_account = get_account(fee.FeeType)
"charge_type":"Actual", charges_fees.get("fees").append({
"account_head": fee_account, "charge_type":"Actual",
"tax_amount": fee.FeeAmount.CurrencyAmount, "account_head": fee_account,
"description": fee.FeeType + " for " + shipment_item.SellerSKU "tax_amount": fee.FeeAmount.CurrencyAmount,
}) "description": fee.FeeType + " for " + shipment_item.SellerSKU
})
return charges_fees return charges_fees

View File

@@ -65,7 +65,7 @@ class WoocommerceSettings(Document):
if not frappe.get_value("Item Group",{"name": "WooCommerce Products"}): if not frappe.get_value("Item Group",{"name": "WooCommerce Products"}):
item_group = frappe.new_doc("Item Group") item_group = frappe.new_doc("Item Group")
item_group.item_group_name = "WooCommerce Products" item_group.item_group_name = "WooCommerce Products"
item_group.parent_item_group = "All Item Groups" item_group.parent_item_group = _("All Item Groups")
item_group.save() item_group.save()

View File

@@ -123,10 +123,10 @@ var btn_invoice_registration = function (frm) {
frappe.ui.form.on('Patient Relation', { frappe.ui.form.on('Patient Relation', {
patient_relation_add: function(frm){ patient_relation_add: function(frm){
frm.fields_dict['patient_relation'].grid.get_field('patient').get_query = function(frm){ frm.fields_dict['patient_relation'].grid.get_field('patient').get_query = function(doc){
var patient_list = []; var patient_list = [];
if(!frm.doc.__islocal) patient_list.push(frm.doc.name); if(!doc.__islocal) patient_list.push(doc.name);
$.each(frm.doc.patient_relation, function(idx, val){ $.each(doc.patient_relation, function(idx, val){
if (val.patient) patient_list.push(val.patient); if (val.patient) patient_list.push(val.patient);
}); });
return { filters: [['Patient', 'name', 'not in', patient_list]] }; return { filters: [['Patient', 'name', 'not in', patient_list]] };

View File

@@ -512,7 +512,7 @@ def add_department_leaves(events, start, end, employee, company):
department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s department_employees = frappe.db.sql_list("""select name from tabEmployee where department=%s
and company=%s""", (department, company)) and company=%s""", (department, company))
filter_conditions = "employee in (\"%s\")" % '", "'.join(department_employees) filter_conditions = " and employee in (\"%s\")" % '", "'.join(department_employees)
add_leaves(events, start, end, filter_conditions=filter_conditions) add_leaves(events, start, end, filter_conditions=filter_conditions)
def add_leaves(events, start, end, filter_conditions=None): def add_leaves(events, start, end, filter_conditions=None):

View File

@@ -15,9 +15,11 @@ class TrainingFeedback(Document):
def on_submit(self): def on_submit(self):
training_event = frappe.get_doc("Training Event", self.training_event) training_event = frappe.get_doc("Training Event", self.training_event)
status = None
for e in training_event.employees: for e in training_event.employees:
if e.employee == self.employee: if e.employee == self.employee:
training_event.status = 'Feedback Submitted' status = 'Feedback Submitted'
break break
training_event.save() if status:
frappe.db.set_value("Training Event", self.training_event, "status", status)

View File

@@ -571,7 +571,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", "purchase-analytics")
execute:frappe.delete_doc_if_exists("Page", "stock-analytics") execute:frappe.delete_doc_if_exists("Page", "stock-analytics")
execute:frappe.delete_doc_if_exists("Page", "production-analytics") execute:frappe.delete_doc_if_exists("Page", "production-analytics")
erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 erpnext.patches.v11_0.ewaybill_fields_gst_india #2018-11-13 #2019-01-09 #2019-04-01
erpnext.patches.v11_0.drop_column_max_days_allowed erpnext.patches.v11_0.drop_column_max_days_allowed
erpnext.patches.v11_0.change_healthcare_desktop_icons erpnext.patches.v11_0.change_healthcare_desktop_icons
erpnext.patches.v10_0.update_user_image_in_employee erpnext.patches.v10_0.update_user_image_in_employee
@@ -589,3 +589,4 @@ erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019 erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
erpnext.patches.v11_1.make_job_card_time_logs erpnext.patches.v11_1.make_job_card_time_logs
erpnext.patches.v11_1.set_variant_based_on

View File

@@ -0,0 +1,11 @@
# 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
def execute():
frappe.db.sql("""update tabItem set variant_based_on = 'Item Attribute'
where ifnull(variant_based_on, '') = ''
and (has_variants=1 or ifnull(variant_of, '') != '')
""")

View File

@@ -0,0 +1,139 @@
# 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 frappe.utils import time_diff_in_hours
def get_columns():
return [
{
"label": _("Employee ID"),
"fieldtype": "Link",
"fieldname": "employee",
"options": "Employee",
"width": 300
},
{
"label": _("Employee Name"),
"fieldtype": "data",
"fieldname": "employee_name",
"hidden": 1,
"width": 200
},
{
"label": _("Timesheet"),
"fieldtype": "Link",
"fieldname": "timesheet",
"options": "Timesheet",
"width": 150
},
{
"label": _("Billable Hours"),
"fieldtype": "Float",
"fieldname": "total_billable_hours",
"width": 50
},
{
"label": _("Working Hours"),
"fieldtype": "Float",
"fieldname": "total_hours",
"width": 50
},
{
"label": _("Amount"),
"fieldtype": "Currency",
"fieldname": "amount",
"width": 100
}
]
def get_data(filters):
data = []
record = get_records(filters)
billable_hours_worked = 0
hours_worked = 0
working_cost = 0
for entries in record:
total_hours = 0
total_billable_hours = 0
total_amount = 0
entries_exists = False
timesheet_details = get_timesheet_details(filters, entries.name)
for activity in timesheet_details:
entries_exists = True
time_start = activity.from_time
time_end = frappe.utils.add_to_date(activity.from_time, hours=activity.hours)
from_date = frappe.utils.get_datetime(filters.from_date)
to_date = frappe.utils.get_datetime(filters.to_date)
if time_start <= from_date and time_end >= from_date:
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
time_end, from_date, total_hours, total_billable_hours, total_amount)
elif time_start <= to_date and time_end >= to_date:
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
to_date, time_start, total_hours, total_billable_hours, total_amount)
elif time_start >= from_date and time_end <= to_date:
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
time_end, time_start, total_hours, total_billable_hours, total_amount)
hours_worked += total_hours
billable_hours_worked += total_billable_hours
working_cost += total_amount
row = {
"employee": entries.employee,
"employee_name": entries.employee_name,
"timesheet": entries.name,
"total_billable_hours": total_billable_hours,
"total_hours": total_hours,
"amount": total_amount
}
if entries_exists:
data.append(row)
entries_exists = False
total = {
"total_billable_hours": billable_hours_worked,
"total_hours": hours_worked,
"amount": working_cost
}
if billable_hours_worked !=0 or hours_worked !=0 or working_cost !=0:
data.append(total)
return data
def get_records(filters):
record_filters = [
["start_date", "<=", filters.to_date],
["end_date", ">=", filters.from_date],
["docstatus", "=", 1]
]
if "employee" in filters:
record_filters.append(["employee", "=", filters.employee])
return frappe.get_all("Timesheet", filters=record_filters, fields=[" * "] )
def get_billable_and_total_hours(activity, end, start, total_hours, total_billable_hours, total_amount):
total_hours += abs(time_diff_in_hours(end, start))
if activity.billable:
total_billable_hours += abs(time_diff_in_hours(end, start))
total_amount += total_billable_hours * activity.billing_rate
return total_hours, total_billable_hours, total_amount
def get_timesheet_details(filters, parent):
timesheet_details_filter = {"parent": parent}
if "project" in filters:
timesheet_details_filter["project"] = filters.project
return frappe.get_all(
"Timesheet Detail",
filters = timesheet_details_filter,
fields=["*"]
)

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Employee Billing Summary"] = {
"filters": [
{
fieldname: "employee",
label: __("Employee"),
fieldtype: "Link",
options: "Employee",
reqd: 1
},
{
fieldname:"from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
reqd: 1
},
{
fieldname:"to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.datetime.add_days(frappe.datetime.month_start(), -1),
reqd: 1
},
]
}

View File

@@ -0,0 +1,36 @@
{
"add_total_row": 0,
"creation": "2019-03-08 15:08:19.929728",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-03-08 15:08:19.929728",
"modified_by": "Administrator",
"module": "Projects",
"name": "Employee Billing Summary",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Timesheet",
"report_name": "Employee Billing Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Projects User"
},
{
"role": "HR User"
},
{
"role": "Manufacturing User"
},
{
"role": "Employee"
},
{
"role": "Accounts User"
}
]
}

View File

@@ -0,0 +1,14 @@
# 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.projects.report.billing_summary import get_columns, get_data
def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns()
data = get_data(filters)
return columns, data

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Project Billing Summary"] = {
"filters": [
{
fieldname: "project",
label: __("Project"),
fieldtype: "Link",
options: "Project",
reqd: 1
},
{
fieldname:"from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.datetime.add_months(frappe.datetime.month_start(), -1),
reqd: 1
},
{
fieldname:"to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.datetime.add_days(frappe.datetime.month_start(),-1),
reqd: 1
},
]
}

View File

@@ -0,0 +1,36 @@
{
"add_total_row": 0,
"creation": "2019-03-11 16:22:39.460524",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2019-03-11 16:22:39.460524",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Billing Summary",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Timesheet",
"report_name": "Project Billing Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Projects User"
},
{
"role": "HR User"
},
{
"role": "Manufacturing User"
},
{
"role": "Employee"
},
{
"role": "Accounts User"
}
]
}

View File

@@ -0,0 +1,14 @@
# 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.projects.report.billing_summary import get_columns, get_data
def execute(filters=None):
filters = frappe._dict(filters or {})
columns = get_columns()
data = get_data(filters)
return columns, data

View File

@@ -93,7 +93,7 @@ def add_print_formats():
def make_custom_fields(update=True): def make_custom_fields(update=True):
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC', hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description', fieldtype='Data', fetch_from='item_code.gst_hsn_code', insert_after='description',
allow_on_submit=1, print_hide=1) allow_on_submit=1, print_hide=1, fetch_if_empty=1)
invoice_gst_fields = [ invoice_gst_fields = [
dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break', dict(fieldname='gst_section', label='GST Details', fieldtype='Section Break',
insert_after='language', print_hide=1, collapsible=1), insert_after='language', print_hide=1, collapsible=1),
@@ -243,6 +243,7 @@ def make_custom_fields(update=True):
'Purchase Order Item': [hsn_sac_field], 'Purchase Order Item': [hsn_sac_field],
'Purchase Receipt Item': [hsn_sac_field], 'Purchase Receipt Item': [hsn_sac_field],
'Purchase Invoice Item': [hsn_sac_field], 'Purchase Invoice Item': [hsn_sac_field],
'Material Request Item': [hsn_sac_field],
'Employee': [ 'Employee': [
dict(fieldname='ifsc_code', label='IFSC Code', dict(fieldname='ifsc_code', label='IFSC Code',
fieldtype='Data', insert_after='bank_ac_no', print_hide=1, fieldtype='Data', insert_after='bank_ac_no', print_hide=1,

View File

@@ -184,11 +184,7 @@
<UnitaMisura>{{ item.stock_uom }}</UnitaMisura> <UnitaMisura>{{ item.stock_uom }}</UnitaMisura>
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario> <PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario>
{{ render_discount_or_margin(item) }} {{ render_discount_or_margin(item) }}
{%- if (item.discount_amount or item.rate_with_margin) %} <PrezzoTotale>{{ format_float(item.amount) }}</PrezzoTotale>
<PrezzoTotale>{{ format_float(item.net_amount) }}</PrezzoTotale>
{%- else %}
<PrezzoTotale>{{ format_float(item.amount) }}</PrezzoTotale>
{%- endif %}
<AliquotaIVA>{{ format_float(item.tax_rate) }}</AliquotaIVA> <AliquotaIVA>{{ format_float(item.tax_rate) }}</AliquotaIVA>
{%- if item.tax_exemption_reason %} {%- if item.tax_exemption_reason %}
<Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura> <Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura>

View File

@@ -4,6 +4,7 @@ import frappe, json, os
from frappe.utils import flt, cstr from frappe.utils import flt, cstr
from erpnext.controllers.taxes_and_totals import get_itemised_tax from erpnext.controllers.taxes_and_totals import get_itemised_tax
from frappe import _ from frappe import _
from six import string_types
from frappe.utils.file_manager import save_file, remove_file from frappe.utils.file_manager import save_file, remove_file
from frappe.desk.form.load import get_attachments from frappe.desk.form.load import get_attachments
from erpnext.regional.italy import state_codes from erpnext.regional.italy import state_codes
@@ -151,7 +152,7 @@ def get_invoice_summary(items, taxes):
tax_amount=(reference_row.tax_amount * tax.rate) / 100, tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount, net_amount=reference_row.tax_amount,
taxable_amount=reference_row.tax_amount, taxable_amount=reference_row.tax_amount,
item_tax_rate="{}", item_tax_rate={tax.account_head: tax.rate},
charges=True charges=True
) )
) )
@@ -159,10 +160,16 @@ def get_invoice_summary(items, taxes):
#Check item tax rates if tax rate is zero. #Check item tax rates if tax rate is zero.
if tax.rate == 0: if tax.rate == 0:
for item in items: for item in items:
item_tax_rate = json.loads(item.item_tax_rate) item_tax_rate = item.item_tax_rate
if tax.account_head in item_tax_rate: if isinstance(item.item_tax_rate, string_types):
item_tax_rate = json.loads(item.item_tax_rate)
if item_tax_rate and tax.account_head in item_tax_rate:
key = cstr(item_tax_rate[tax.account_head]) key = cstr(item_tax_rate[tax.account_head])
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, "tax_exemption_reason": "", "tax_exemption_law": ""}) if key not in summary_data:
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0,
"tax_exemption_reason": "", "tax_exemption_law": ""})
summary_data[key]["tax_amount"] += item.tax_amount summary_data[key]["tax_amount"] += item.tax_amount
summary_data[key]["taxable_amount"] += item.net_amount summary_data[key]["taxable_amount"] += item.net_amount
if key == "0.0": if key == "0.0":

View File

@@ -612,7 +612,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False):
def postprocess(source, target): def postprocess(source, target):
set_missing_values(source, target) set_missing_values(source, target)
#Get the advance paid Journal Entries in Sales Invoice Advance #Get the advance paid Journal Entries in Sales Invoice Advance
target.set_advances() if target.get("allocate_advances_automatically"):
target.set_advances()
def set_missing_values(source, target): def set_missing_values(source, target):
target.is_pos = 0 target.is_pos = 0

View File

@@ -446,16 +446,15 @@ erpnext.pos.PointOfSale = class PointOfSale {
} }
setup_company() { setup_company() {
this.company = frappe.sys_defaults.company;
return new Promise(resolve => { return new Promise(resolve => {
if(!this.company) { if(!frappe.sys_defaults.company) {
frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link", frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link",
label: __("Select Company"), reqd: 1}, (data) => { label: __("Select Company"), reqd: 1}, (data) => {
this.company = data.company; this.company = data.company;
resolve(this.company); resolve(this.company);
}, __("Select Company")); }, __("Select Company"));
} else { } else {
resolve(this.company); resolve();
} }
}) })
} }
@@ -509,7 +508,9 @@ erpnext.pos.PointOfSale = class PointOfSale {
} }
set_pos_profile_data() { set_pos_profile_data() {
this.frm.doc.company = this.company; if (this.company) {
this.frm.doc.company = this.company;
}
return new Promise(resolve => { return new Promise(resolve => {
return this.frm.call({ return this.frm.call({

View File

@@ -39,7 +39,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
if display_items_in_stock == 0: if display_items_in_stock == 0:
res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image, res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image, i.idx as idx,
i.is_stock_item, item_det.price_list_rate, item_det.currency i.is_stock_item, item_det.price_list_rate, item_det.currency
from `tabItem` i LEFT JOIN from `tabItem` i LEFT JOIN
(select item_code, price_list_rate, currency from (select item_code, price_list_rate, currency from
@@ -49,7 +49,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
where where
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt}) and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt})
and {condition} limit {start}, {page_length}""".format(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition), and {condition} order by idx desc limit {start}, {page_length}""".format(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
{ {
'item_code': item_code, 'item_code': item_code,
'price_list': price_list 'price_list': price_list
@@ -60,7 +60,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
} }
elif display_items_in_stock == 1: elif display_items_in_stock == 1:
query = """select i.name as item_code, i.item_name, i.image as item_image, query = """select i.name as item_code, i.item_name, i.image as item_image, i.idx as idx,
i.is_stock_item, item_det.price_list_rate, item_det.currency i.is_stock_item, item_det.price_list_rate, item_det.currency
from `tabItem` i LEFT JOIN from `tabItem` i LEFT JOIN
(select item_code, price_list_rate, currency from (select item_code, price_list_rate, currency from
@@ -79,7 +79,7 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
where where
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt}) and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt})
and {condition} limit {start}, {page_length}""".format and {condition} order by idx desc limit {start}, {page_length}""".format
(start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition), (start=start,page_length=page_length,lft=lft, rgt=rgt, condition=condition),
{ {
'item_code': item_code, 'item_code': item_code,

View File

@@ -47,9 +47,8 @@ def get_columns():
}, },
{ {
"label": _("Material Request"), "label": _("Material Request"),
"options": "Material Request",
"fieldname": "material_request", "fieldname": "material_request",
"fieldtype": "Link", "fieldtype": "Data",
"width": 140 "width": 140
}, },
{ {
@@ -116,33 +115,43 @@ def get_data():
{"sales_order_item": ("!=",""), "docstatus": 1}, {"sales_order_item": ("!=",""), "docstatus": 1},
["parent", "qty", "sales_order", "item_code"]) ["parent", "qty", "sales_order", "item_code"])
grouped_records = {} materials_request_dict = {}
for record in mr_records: for record in mr_records:
grouped_records.setdefault(record.sales_order, []).append(record) key = (record.sales_order, record.item_code)
if key not in materials_request_dict:
materials_request_dict.setdefault(key, {
'qty': 0,
'material_requests': [record.parent]
})
details = materials_request_dict.get(key)
details['qty'] += record.qty
if record.parent not in details.get('material_requests'):
details['material_requests'].append(record.parent)
pending_so=[] pending_so=[]
for so in sales_order_entry: for so in sales_order_entry:
# fetch all the material request records for a sales order item # fetch all the material request records for a sales order item
mr_list = grouped_records.get(so.name) or [{}] key = (so.name, so.item_code)
mr_item_record = ([mr for mr in mr_list if mr.get('item_code') == so.item_code] or [{}]) materials_request = materials_request_dict.get(key) or {}
for mr in mr_item_record: # check for pending sales order
# check for pending sales order if cint(so.net_qty) > cint(materials_request.get('qty')):
if cint(so.net_qty) > cint(mr.get('qty')): so_record = {
so_record = { "item_code": so.item_code,
"item_code": so.item_code, "item_name": so.item_name,
"item_name": so.item_name, "description": so.description,
"description": so.description, "sales_order_no": so.name,
"sales_order_no": so.name, "date": so.transaction_date,
"date": so.transaction_date, "material_request": ','.join(materials_request.get('material_requests', [])),
"material_request": cstr(mr.get('parent')), "customer": so.customer,
"customer": so.customer, "territory": so.territory,
"territory": so.territory, "so_qty": so.net_qty,
"so_qty": so.net_qty, "requested_qty": cint(materials_request.get('qty')),
"requested_qty": cint(mr.get('qty')), "pending_qty": so.net_qty - cint(materials_request.get('qty')),
"pending_qty": so.net_qty - cint(mr.get('qty')), "company": so.company
"company": so.company }
} pending_so.append(so_record)
pending_so.append(so_record)
return pending_so return pending_so

View File

@@ -377,7 +377,7 @@ def replace_abbr(company, old, new):
for d in doc: for d in doc:
_rename_record(d) _rename_record(d)
for dt in ["Warehouse", "Account", "Cost Center", "Department", "Location", for dt in ["Warehouse", "Account", "Cost Center", "Department",
"Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]: "Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
_rename_records(dt) _rename_records(dt)
frappe.db.commit() frappe.db.commit()

View File

@@ -12,7 +12,6 @@ from frappe.website.render import clear_cache
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
from erpnext.shopping_cart.product_info import set_product_info_for_website from erpnext.shopping_cart.product_info import set_product_info_for_website
from erpnext.utilities.product import get_qty_in_stock from erpnext.utilities.product import get_qty_in_stock
from frappe.utils.html_utils import clean_html
class ItemGroup(NestedSet, WebsiteGenerator): class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group' nsm_parent_field = 'parent_item_group'
@@ -27,7 +26,6 @@ class ItemGroup(NestedSet, WebsiteGenerator):
def validate(self): def validate(self):
super(ItemGroup, self).validate() super(ItemGroup, self).validate()
self.description = clean_html(self.description)
self.make_route() self.make_route()
def on_update(self): def on_update(self):

View File

@@ -22,6 +22,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "name_and_employee_id", "fieldname": "name_and_employee_id",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -54,6 +55,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_person_name", "fieldname": "sales_person_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -88,6 +90,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Select company name first.", "description": "Select company name first.",
"fetch_if_empty": 0,
"fieldname": "parent_sales_person", "fieldname": "parent_sales_person",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -122,6 +125,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "commission_rate", "fieldname": "commission_rate",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -154,6 +158,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "is_group", "fieldname": "is_group",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -189,6 +194,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"fetch_if_empty": 0,
"fieldname": "enabled", "fieldname": "enabled",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -221,6 +227,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "cb0", "fieldname": "cb0",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -251,6 +258,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "employee", "fieldname": "employee",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -270,7 +278,7 @@
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@@ -284,6 +292,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "employee.department", "fetch_from": "employee.department",
"fetch_if_empty": 0,
"fieldname": "department", "fieldname": "department",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -317,6 +326,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "lft", "fieldname": "lft",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 1, "hidden": 1,
@@ -350,6 +360,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "rgt", "fieldname": "rgt",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 1, "hidden": 1,
@@ -383,6 +394,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "old_parent", "fieldname": "old_parent",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -417,6 +429,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Set targets Item Group-wise for this Sales Person.", "description": "Set targets Item Group-wise for this Sales Person.",
"fetch_if_empty": 0,
"fieldname": "target_details_section_break", "fieldname": "target_details_section_break",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -450,6 +463,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "targets", "fieldname": "targets",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -485,6 +499,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Select Monthly Distribution to unevenly distribute targets across months.", "description": "Select Monthly Distribution to unevenly distribute targets across months.",
"fetch_if_empty": 0,
"fieldname": "distribution_id", "fieldname": "distribution_id",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -524,7 +539,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2019-01-30 11:28:16.966735", "modified": "2019-04-09 20:03:35.967037",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Sales Person", "name": "Sales Person",
@@ -594,7 +609,7 @@
"search_fields": "parent_sales_person", "search_fields": "parent_sales_person",
"show_name_in_global_search": 1, "show_name_in_global_search": 1,
"sort_order": "ASC", "sort_order": "ASC",
"track_changes": 1, "track_changes": 0,
"track_seen": 0, "track_seen": 0,
"track_views": 0 "track_views": 0
} }

View File

@@ -48,10 +48,11 @@ class SalesPerson(NestedSet):
return frappe.db.get_value("User", user, "email") or user return frappe.db.get_value("User", user, "email") or user
def validate_employee_id(self): def validate_employee_id(self):
sales_person = frappe.db.get_value("Sales Person", {"employee": self.employee}) if self.employee:
sales_person = frappe.db.get_value("Sales Person", {"employee": self.employee})
if sales_person and sales_person != self.name: if sales_person and sales_person != self.name:
frappe.throw(_("Another Sales Person {0} exists with the same Employee id").format(sales_person)) frappe.throw(_("Another Sales Person {0} exists with the same Employee id").format(sales_person))
def on_doctype_update(): def on_doctype_update():
frappe.db.add_index("Sales Person", ["lft", "rgt"]) frappe.db.add_index("Sales Person", ["lft", "rgt"])
@@ -97,5 +98,3 @@ def get_timeline_data(doctype, name):
out[key] = delivery_note[key] out[key] = delivery_note[key]
return out return out

View File

@@ -23,6 +23,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "name_and_description_section", "fieldname": "name_and_description_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -57,6 +58,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -91,6 +93,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -127,6 +130,7 @@
"columns": 0, "columns": 0,
"depends_on": "variant_of", "depends_on": "variant_of",
"description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified", "description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified",
"fetch_if_empty": 0,
"fieldname": "variant_of", "fieldname": "variant_of",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -160,6 +164,7 @@
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_name", "fieldname": "item_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -195,6 +200,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "item_group", "fieldname": "item_group",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -230,6 +236,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "is_item_from_hub", "fieldname": "is_item_from_hub",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -263,6 +270,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "stock_uom", "fieldname": "stock_uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -298,6 +306,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break0", "fieldname": "column_break0",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -329,6 +338,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "disabled", "fieldname": "disabled",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -361,6 +371,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "allow_alternative_item", "fieldname": "allow_alternative_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -395,6 +406,7 @@
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "is_stock_item", "fieldname": "is_stock_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -431,6 +443,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"fetch_if_empty": 0,
"fieldname": "include_item_in_manufacturing", "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -464,6 +477,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)",
"fetch_if_empty": 0,
"fieldname": "opening_stock", "fieldname": "opening_stock",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -497,6 +511,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "valuation_rate", "fieldname": "valuation_rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -530,6 +545,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.__islocal", "depends_on": "eval:doc.__islocal",
"fetch_if_empty": 0,
"fieldname": "standard_rate", "fieldname": "standard_rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
@@ -562,6 +578,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "is_fixed_asset", "fieldname": "is_fixed_asset",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -595,6 +612,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_fixed_asset", "depends_on": "is_fixed_asset",
"fetch_if_empty": 0,
"fieldname": "asset_category", "fieldname": "asset_category",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -629,6 +647,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_fixed_asset", "depends_on": "is_fixed_asset",
"fetch_if_empty": 0,
"fieldname": "asset_naming_series", "fieldname": "asset_naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -663,6 +682,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval:!doc.__islocal", "depends_on": "eval:!doc.__islocal",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "tolerance", "fieldname": "tolerance",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -697,6 +717,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "image", "fieldname": "image",
"fieldtype": "Attach Image", "fieldtype": "Attach Image",
"hidden": 1, "hidden": 1,
@@ -730,6 +751,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "section_break_11", "fieldname": "section_break_11",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -762,6 +784,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "brand", "fieldname": "brand",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -797,6 +820,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"hidden": 0, "hidden": 0,
@@ -831,6 +855,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sb_barcodes", "fieldname": "sb_barcodes",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -863,6 +888,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "barcodes", "fieldname": "barcodes",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -898,6 +924,7 @@
"collapsible_depends_on": "is_stock_item", "collapsible_depends_on": "is_stock_item",
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "inventory_section", "fieldname": "inventory_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -932,6 +959,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "shelf_life_in_days", "fieldname": "shelf_life_in_days",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -966,6 +994,7 @@
"columns": 0, "columns": 0,
"default": "2099-12-31", "default": "2099-12-31",
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "end_of_life", "fieldname": "end_of_life",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0, "hidden": 0,
@@ -1001,6 +1030,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "Purchase", "default": "Purchase",
"fetch_if_empty": 0,
"fieldname": "default_material_request_type", "fieldname": "default_material_request_type",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -1035,6 +1065,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "valuation_method", "fieldname": "valuation_method",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -1069,6 +1100,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "column_break1", "fieldname": "column_break1",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1103,6 +1135,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_stock_item", "depends_on": "eval:doc.is_stock_item",
"fetch_if_empty": 0,
"fieldname": "warranty_period", "fieldname": "warranty_period",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -1139,6 +1172,7 @@
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "weight_per_unit", "fieldname": "weight_per_unit",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -1172,6 +1206,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_stock_item", "depends_on": "eval:doc.is_stock_item",
"fetch_if_empty": 0,
"fieldname": "weight_uom", "fieldname": "weight_uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1207,6 +1242,7 @@
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "reorder_section", "fieldname": "reorder_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1242,6 +1278,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "Will also apply for variants unless overrridden", "description": "Will also apply for variants unless overrridden",
"fetch_if_empty": 0,
"fieldname": "reorder_levels", "fieldname": "reorder_levels",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1276,6 +1313,7 @@
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "unit_of_measure_conversion", "fieldname": "unit_of_measure_conversion",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1310,6 +1348,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "Will also apply for variants", "description": "Will also apply for variants",
"fetch_if_empty": 0,
"fieldname": "uoms", "fieldname": "uoms",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1347,6 +1386,7 @@
"collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no || doc.is_fixed_asset", "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no || doc.is_fixed_asset",
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset", "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
"fetch_if_empty": 0,
"fieldname": "serial_nos_and_batches", "fieldname": "serial_nos_and_batches",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1381,6 +1421,7 @@
"columns": 0, "columns": 0,
"default": "", "default": "",
"depends_on": "eval:doc.is_stock_item", "depends_on": "eval:doc.is_stock_item",
"fetch_if_empty": 0,
"fieldname": "has_batch_no", "fieldname": "has_batch_no",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1418,6 +1459,7 @@
"columns": 0, "columns": 0,
"depends_on": "has_batch_no", "depends_on": "has_batch_no",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "create_new_batch", "fieldname": "create_new_batch",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1452,6 +1494,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval:doc.has_batch_no==1 && doc.create_new_batch==1", "depends_on": "eval:doc.has_batch_no==1 && doc.create_new_batch==1",
"description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions,then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item,leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.", "description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions,then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item,leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.",
"fetch_if_empty": 0,
"fieldname": "batch_number_series", "fieldname": "batch_number_series",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -1485,6 +1528,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "has_batch_no", "depends_on": "has_batch_no",
"fetch_if_empty": 0,
"fieldname": "has_expiry_date", "fieldname": "has_expiry_date",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1518,6 +1562,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "has_batch_no", "depends_on": "has_batch_no",
"fetch_if_empty": 0,
"fieldname": "retain_sample", "fieldname": "retain_sample",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1552,6 +1597,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: (doc.retain_sample && doc.has_batch_no)", "depends_on": "eval: (doc.retain_sample && doc.has_batch_no)",
"description": "Maximum sample quantity that can be retained", "description": "Maximum sample quantity that can be retained",
"fetch_if_empty": 0,
"fieldname": "sample_quantity", "fieldname": "sample_quantity",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -1584,6 +1630,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_37", "fieldname": "column_break_37",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -1618,6 +1665,7 @@
"default": "", "default": "",
"depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset", "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "has_serial_no", "fieldname": "has_serial_no",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1655,6 +1703,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset", "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
"description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions,then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.", "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions,then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.",
"fetch_if_empty": 0,
"fieldname": "serial_no_series", "fieldname": "serial_no_series",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -1689,6 +1738,7 @@
"collapsible_depends_on": "attributes", "collapsible_depends_on": "attributes",
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "variants_section", "fieldname": "variants_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1724,6 +1774,7 @@
"default": "0", "default": "0",
"depends_on": "eval:!doc.variant_of", "depends_on": "eval:!doc.variant_of",
"description": "If this item has variants,then it cannot be selected in sales orders etc.", "description": "If this item has variants,then it cannot be selected in sales orders etc.",
"fetch_if_empty": 0,
"fieldname": "has_variants", "fieldname": "has_variants",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1759,6 +1810,7 @@
"columns": 0, "columns": 0,
"default": "Item Attribute", "default": "Item Attribute",
"depends_on": "has_variants", "depends_on": "has_variants",
"fetch_if_empty": 0,
"fieldname": "variant_based_on", "fieldname": "variant_based_on",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
@@ -1781,7 +1833,7 @@
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 1, "set_only_once": 0,
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
@@ -1793,6 +1845,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.has_variants || doc.variant_of) && doc.variant_based_on==='Item Attribute'", "depends_on": "eval:(doc.has_variants || doc.variant_of) && doc.variant_based_on==='Item Attribute'",
"fetch_if_empty": 0,
"fieldname": "attributes", "fieldname": "attributes",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 1, "hidden": 1,
@@ -1826,6 +1879,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "defaults", "fieldname": "defaults",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1858,6 +1912,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_defaults", "fieldname": "item_defaults",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -1891,6 +1946,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "purchase_details", "fieldname": "purchase_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -1926,6 +1982,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"fetch_if_empty": 0,
"fieldname": "is_purchase_item", "fieldname": "is_purchase_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -1958,6 +2015,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "purchase_uom", "fieldname": "purchase_uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -1994,6 +2052,7 @@
"default": "0.00", "default": "0.00",
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "min_order_qty", "fieldname": "min_order_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -2028,6 +2087,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "safety_stock", "fieldname": "safety_stock",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -2060,6 +2120,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "purchase_details_cb", "fieldname": "purchase_details_cb",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2094,6 +2155,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "Average time taken by the supplier to deliver", "description": "Average time taken by the supplier to deliver",
"fetch_if_empty": 0,
"fieldname": "lead_time_days", "fieldname": "lead_time_days",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -2129,6 +2191,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "last_purchase_rate", "fieldname": "last_purchase_rate",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -2164,6 +2227,7 @@
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "supplier_details", "fieldname": "supplier_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2196,6 +2260,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "delivered_by_supplier", "fieldname": "delivered_by_supplier",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -2229,6 +2294,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "manufacturer", "fieldname": "manufacturer",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2263,6 +2329,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "manufacturer_part_no", "fieldname": "manufacturer_part_no",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -2296,6 +2363,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "column_break2", "fieldname": "column_break2",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2331,6 +2399,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "supplier_items", "fieldname": "supplier_items",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -2364,6 +2433,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "foreign_trade_details", "fieldname": "foreign_trade_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2396,6 +2466,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "country_of_origin", "fieldname": "country_of_origin",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2429,6 +2500,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_59", "fieldname": "column_break_59",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2460,6 +2532,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "customs_tariff_number", "fieldname": "customs_tariff_number",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2493,6 +2566,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_details", "fieldname": "sales_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2527,6 +2601,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "sales_uom", "fieldname": "sales_uom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2561,6 +2636,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "1", "default": "1",
"fetch_if_empty": 0,
"fieldname": "is_sales_item", "fieldname": "is_sales_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -2594,6 +2670,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "column_break3", "fieldname": "column_break3",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2629,6 +2706,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "max_discount", "fieldname": "max_discount",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0, "hidden": 0,
@@ -2663,6 +2741,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "deferred_revenue", "fieldname": "deferred_revenue",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2696,6 +2775,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "enable_deferred_revenue", "depends_on": "enable_deferred_revenue",
"fetch_if_empty": 0,
"fieldname": "deferred_revenue_account", "fieldname": "deferred_revenue_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2729,6 +2809,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "enable_deferred_revenue", "fieldname": "enable_deferred_revenue",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -2761,6 +2842,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_85", "fieldname": "column_break_85",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2793,6 +2875,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "enable_deferred_revenue", "depends_on": "enable_deferred_revenue",
"fetch_if_empty": 0,
"fieldname": "no_of_months", "fieldname": "no_of_months",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -2825,6 +2908,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "deferred_expense_section", "fieldname": "deferred_expense_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -2858,6 +2942,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "enable_deferred_expense", "depends_on": "enable_deferred_expense",
"fetch_if_empty": 0,
"fieldname": "deferred_expense_account", "fieldname": "deferred_expense_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -2891,6 +2976,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "enable_deferred_expense", "fieldname": "enable_deferred_expense",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -2923,6 +3009,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_88", "fieldname": "column_break_88",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -2955,6 +3042,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "enable_deferred_expense", "depends_on": "enable_deferred_expense",
"fetch_if_empty": 0,
"fieldname": "no_of_months_exp", "fieldname": "no_of_months_exp",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -2987,6 +3075,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_details", "fieldname": "customer_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3021,6 +3110,7 @@
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "", "description": "",
"fetch_if_empty": 0,
"fieldname": "customer_items", "fieldname": "customer_items",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -3054,6 +3144,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "item_tax_section_break", "fieldname": "item_tax_section_break",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3089,6 +3180,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Will also apply for variants", "description": "Will also apply for variants",
"fetch_if_empty": 0,
"fieldname": "taxes", "fieldname": "taxes",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -3124,6 +3216,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "inspection_criteria", "fieldname": "inspection_criteria",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3159,6 +3252,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "inspection_required_before_purchase", "fieldname": "inspection_required_before_purchase",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -3194,6 +3288,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "inspection_required_before_delivery", "fieldname": "inspection_required_before_delivery",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -3227,6 +3322,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)", "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
"fetch_if_empty": 0,
"fieldname": "quality_inspection_template", "fieldname": "quality_inspection_template",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3261,6 +3357,7 @@
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"depends_on": "is_stock_item", "depends_on": "is_stock_item",
"fetch_if_empty": 0,
"fieldname": "manufacturing", "fieldname": "manufacturing",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3296,6 +3393,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"fetch_if_empty": 0,
"fieldname": "default_bom", "fieldname": "default_bom",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3333,6 +3431,7 @@
"columns": 0, "columns": 0,
"default": "", "default": "",
"description": "If subcontracted to a vendor", "description": "If subcontracted to a vendor",
"fetch_if_empty": 0,
"fieldname": "is_sub_contracted_item", "fieldname": "is_sub_contracted_item",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -3368,6 +3467,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_74", "fieldname": "column_break_74",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -3399,6 +3499,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "customer_code", "fieldname": "customer_code",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -3431,6 +3532,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "website_section", "fieldname": "website_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3465,6 +3567,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:!doc.variant_of", "depends_on": "eval:!doc.variant_of",
"fetch_if_empty": 0,
"fieldname": "show_in_website", "fieldname": "show_in_website",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -3498,6 +3601,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "variant_of", "depends_on": "variant_of",
"fetch_if_empty": 0,
"fieldname": "show_variant_in_website", "fieldname": "show_variant_in_website",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -3531,6 +3635,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fetch_if_empty": 0,
"fieldname": "route", "fieldname": "route",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
@@ -3565,6 +3670,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"description": "Items with higher weightage will be shown higher", "description": "Items with higher weightage will be shown higher",
"fetch_if_empty": 0,
"fieldname": "weightage", "fieldname": "weightage",
"fieldtype": "Int", "fieldtype": "Int",
"hidden": 0, "hidden": 0,
@@ -3599,6 +3705,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"description": "Show a slideshow at the top of the page", "description": "Show a slideshow at the top of the page",
"fetch_if_empty": 0,
"fieldname": "slideshow", "fieldname": "slideshow",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3634,6 +3741,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"description": "Item Image (if not slideshow)", "description": "Item Image (if not slideshow)",
"fetch_if_empty": 0,
"fieldname": "website_image", "fieldname": "website_image",
"fieldtype": "Attach", "fieldtype": "Attach",
"hidden": 0, "hidden": 0,
@@ -3667,6 +3775,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "thumbnail", "fieldname": "thumbnail",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -3699,6 +3808,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "cb72", "fieldname": "cb72",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -3732,6 +3842,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.", "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.",
"fetch_if_empty": 0,
"fieldname": "website_warehouse", "fieldname": "website_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -3767,6 +3878,7 @@
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"description": "List this Item in multiple groups on the website.", "description": "List this Item in multiple groups on the website.",
"fetch_if_empty": 0,
"fieldname": "website_item_groups", "fieldname": "website_item_groups",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -3802,6 +3914,7 @@
"collapsible_depends_on": "website_specifications", "collapsible_depends_on": "website_specifications",
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fetch_if_empty": 0,
"fieldname": "sb72", "fieldname": "sb72",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -3835,6 +3948,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fetch_if_empty": 0,
"fieldname": "copy_from_item_group", "fieldname": "copy_from_item_group",
"fieldtype": "Button", "fieldtype": "Button",
"hidden": 0, "hidden": 0,
@@ -3868,6 +3982,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fetch_if_empty": 0,
"fieldname": "website_specifications", "fieldname": "website_specifications",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@@ -3902,6 +4017,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
"fetch_if_empty": 0,
"fieldname": "web_long_description", "fieldname": "web_long_description",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"hidden": 0, "hidden": 0,
@@ -3934,6 +4050,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "total_projected_qty", "fieldname": "total_projected_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 1, "hidden": 1,
@@ -3967,6 +4084,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "eval:(!doc.is_item_from_hub)", "depends_on": "eval:(!doc.is_item_from_hub)",
"fetch_if_empty": 0,
"fieldname": "hub_publishing_sb", "fieldname": "hub_publishing_sb",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -4001,6 +4119,7 @@
"columns": 0, "columns": 0,
"default": "0", "default": "0",
"description": "Publish Item to hub.erpnext.com", "description": "Publish Item to hub.erpnext.com",
"fetch_if_empty": 0,
"fieldname": "publish_in_hub", "fieldname": "publish_in_hub",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -4033,6 +4152,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "hub_category_to_publish", "fieldname": "hub_category_to_publish",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -4067,6 +4187,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.", "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.",
"fetch_if_empty": 0,
"fieldname": "hub_warehouse", "fieldname": "hub_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
@@ -4101,6 +4222,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "0", "default": "0",
"fetch_if_empty": 0,
"fieldname": "synced_with_hub", "fieldname": "synced_with_hub",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
@@ -4139,7 +4261,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 1, "max_attachments": 1,
"modified": "2019-02-16 17:43:56.039611", "modified": "2019-04-05 12:03:24.530849",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Item", "name": "Item",

View File

@@ -9,11 +9,11 @@ import erpnext
import frappe import frappe
import copy import copy
from erpnext.controllers.item_variant import (ItemVariantExistsError, from erpnext.controllers.item_variant import (ItemVariantExistsError,
copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes) copy_attributes_to_variant, get_variant, make_variant_item_code, validate_item_variant_attributes)
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for) from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
from frappe import _, msgprint from frappe import _, msgprint
from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate, from frappe.utils import (cint, cstr, flt, formatdate, get_timestamp, getdate,
now_datetime, random_string, strip) now_datetime, random_string, strip)
from frappe.utils.html_utils import clean_html from frappe.utils.html_utils import clean_html
from frappe.website.doctype.website_slideshow.website_slideshow import \ from frappe.website.doctype.website_slideshow.website_slideshow import \
get_slideshow get_slideshow
@@ -49,9 +49,6 @@ class Item(WebsiteGenerator):
self.set_onload('stock_exists', self.stock_ledger_created()) self.set_onload('stock_exists', self.stock_ledger_created())
self.set_asset_naming_series() self.set_asset_naming_series()
if self.is_fixed_asset:
asset = self.asset_exists()
self.set_onload("asset_exists", True if asset else False)
def set_asset_naming_series(self): def set_asset_naming_series(self):
if not hasattr(self, '_asset_naming_series'): if not hasattr(self, '_asset_naming_series'):
@@ -118,9 +115,9 @@ class Item(WebsiteGenerator):
self.validate_has_variants() self.validate_has_variants()
self.validate_stock_exists_for_template_item() self.validate_stock_exists_for_template_item()
self.validate_asset_exists_for_serialized_asset()
self.validate_attributes() self.validate_attributes()
self.validate_variant_attributes() self.validate_variant_attributes()
self.validate_variant_based_on_change()
self.validate_website_image() self.validate_website_image()
self.make_thumbnail() self.make_thumbnail()
self.validate_fixed_asset() self.validate_fixed_asset()
@@ -128,6 +125,7 @@ class Item(WebsiteGenerator):
self.validate_uom_conversion_factor() self.validate_uom_conversion_factor()
self.validate_item_defaults() self.validate_item_defaults()
self.update_defaults_from_item_group() self.update_defaults_from_item_group()
self.validate_stock_for_has_batch_and_has_serial()
if not self.get("__islocal"): if not self.get("__islocal"):
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
@@ -151,7 +149,7 @@ class Item(WebsiteGenerator):
'''Add a new price''' '''Add a new price'''
if not price_list: if not price_list:
price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list') price_list = (frappe.db.get_single_value('Selling Settings', 'selling_price_list')
or frappe.db.get_value('Price List', _('Standard Selling'))) or frappe.db.get_value('Price List', _('Standard Selling')))
if price_list: if price_list:
item_price = frappe.get_doc({ item_price = frappe.get_doc({
"doctype": "Item Price", "doctype": "Item Price",
@@ -190,7 +188,7 @@ class Item(WebsiteGenerator):
def make_route(self): def make_route(self):
if not self.route: if not self.route:
return cstr(frappe.db.get_value('Item Group', self.item_group, return cstr(frappe.db.get_value('Item Group', self.item_group,
'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5)) 'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
def validate_website_image(self): def validate_website_image(self):
"""Validate if the website image is a public file""" """Validate if the website image is a public file"""
@@ -213,7 +211,7 @@ class Item(WebsiteGenerator):
if not file_doc: if not file_doc:
if not auto_set_website_image: if not auto_set_website_image:
frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found") frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found")
.format(self.website_image, self.name)) .format(self.website_image, self.name))
self.website_image = None self.website_image = None
@@ -314,8 +312,8 @@ class Item(WebsiteGenerator):
# load variants # load variants
# also used in set_attribute_context # also used in set_attribute_context
context.variants = frappe.get_all("Item", context.variants = frappe.get_all("Item",
filters={"variant_of": self.name, "show_variant_in_website": 1}, filters={"variant_of": self.name, "show_variant_in_website": 1},
order_by="name asc") order_by="name asc")
variant = frappe.form_dict.variant variant = frappe.form_dict.variant
if not variant and context.variants: if not variant and context.variants:
@@ -326,7 +324,7 @@ class Item(WebsiteGenerator):
context.variant = frappe.get_doc("Item", variant) context.variant = frappe.get_doc("Item", variant)
for fieldname in ("website_image", "web_long_description", "description", for fieldname in ("website_image", "web_long_description", "description",
"website_specifications"): "website_specifications"):
if context.variant.get(fieldname): if context.variant.get(fieldname):
value = context.variant.get(fieldname) value = context.variant.get(fieldname)
if isinstance(value, list): if isinstance(value, list):
@@ -349,7 +347,7 @@ class Item(WebsiteGenerator):
# load attributes # load attributes
for v in context.variants: for v in context.variants:
v.attributes = frappe.get_all("Item Variant Attribute", v.attributes = frappe.get_all("Item Variant Attribute",
fields=["attribute", "attribute_value"], fields=["attribute", "attribute_value"],
filters={"parent": v.name}) filters={"parent": v.name})
for attr in v.attributes: for attr in v.attributes:
@@ -530,7 +528,7 @@ class Item(WebsiteGenerator):
warehouse += [d.get("warehouse")] warehouse += [d.get("warehouse")]
else: else:
frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}") frappe.throw(_("Row {0}: An Reorder entry already exists for this warehouse {1}")
.format(d.idx, d.warehouse), DuplicateReorderRows) .format(d.idx, d.warehouse), DuplicateReorderRows)
if d.warehouse_reorder_level and not d.warehouse_reorder_qty: if d.warehouse_reorder_level and not d.warehouse_reorder_qty:
frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx)) frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx))
@@ -550,7 +548,7 @@ class Item(WebsiteGenerator):
def update_item_price(self): def update_item_price(self):
frappe.db.sql("""update `tabItem Price` set item_name=%s, frappe.db.sql("""update `tabItem Price` set item_name=%s,
item_description=%s, brand=%s where item_code=%s""", item_description=%s, brand=%s where item_code=%s""",
(self.item_name, self.description, self.brand, self.name)) (self.item_name, self.description, self.brand, self.name))
def on_trash(self): def on_trash(self):
super(Item, self).on_trash() super(Item, self).on_trash()
@@ -572,7 +570,7 @@ class Item(WebsiteGenerator):
new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)] new_properties = [cstr(d) for d in frappe.db.get_value("Item", new_name, field_list)]
if new_properties != [cstr(self.get(fld)) for fld in field_list]: if new_properties != [cstr(self.get(fld)) for fld in field_list]:
frappe.throw(_("To merge, following properties must be same for both items") frappe.throw(_("To merge, following properties must be same for both items")
+ ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list])) + ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
def after_rename(self, old_name, new_name, merge): def after_rename(self, old_name, new_name, merge):
if self.route: if self.route:
@@ -595,7 +593,7 @@ class Item(WebsiteGenerator):
item_wise_tax_detail.pop(old_name) item_wise_tax_detail.pop(old_name)
frappe.db.set_value(dt, d.name, "item_wise_tax_detail", frappe.db.set_value(dt, d.name, "item_wise_tax_detail",
json.dumps(item_wise_tax_detail), update_modified=False) json.dumps(item_wise_tax_detail), update_modified=False)
def set_last_purchase_rate(self, new_name): def set_last_purchase_rate(self, new_name):
last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0) last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0)
@@ -623,7 +621,7 @@ class Item(WebsiteGenerator):
self.set("website_specifications", []) self.set("website_specifications", [])
if self.item_group: if self.item_group:
for label, desc in frappe.db.get_values("Item Website Specification", for label, desc in frappe.db.get_values("Item Website Specification",
{"parent": self.item_group}, ["label", "description"]): {"parent": self.item_group}, ["label", "description"]):
row = self.append("website_specifications") row = self.append("website_specifications")
row.label = label row.label = label
row.description = desc row.description = desc
@@ -697,7 +695,7 @@ class Item(WebsiteGenerator):
def update_variants(self): def update_variants(self):
if self.flags.dont_update_variants or \ if self.flags.dont_update_variants or \
frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'): frappe.db.get_single_value('Item Variant Settings', 'do_not_update_variants'):
return return
if self.has_variants: if self.has_variants:
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name}) variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name})
@@ -726,17 +724,10 @@ class Item(WebsiteGenerator):
frappe.throw( frappe.throw(
_('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item')) _('Cannot change Attributes after stock transaction. Make a new Item and transfer stock to the new Item'))
def validate_asset_exists_for_serialized_asset(self): def validate_variant_based_on_change(self):
if (not self.get("__islocal") and self.asset_exists() and if not self.is_new() and (self.variant_of or (self.has_variants and frappe.get_all("Item", {"variant_of": self.name}))):
cint(self.has_serial_no) != cint(frappe.db.get_value('Item', self.name, 'has_serial_no'))): if self.variant_based_on != frappe.db.get_value("Item", self.name, "variant_based_on"):
frappe.throw(_("Asset is already exists against the item {0}, you cannot change the has serial no value") frappe.throw(_("Variant Based On cannot be changed"))
.format(self.name))
def asset_exists(self):
if not hasattr(self, '_asset_created'):
self._asset_created = frappe.db.get_all("Asset",
filters={"item_code": self.name, "docstatus": 1}, limit=1)
return self._asset_created
def validate_uom(self): def validate_uom(self):
if not self.get("__islocal"): if not self.get("__islocal"):
@@ -748,7 +739,7 @@ class Item(WebsiteGenerator):
template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom") template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom")
if template_uom != self.stock_uom: if template_uom != self.stock_uom:
frappe.throw(_("Default Unit of Measure for Variant '{0}' must be same as in Template '{1}'") frappe.throw(_("Default Unit of Measure for Variant '{0}' must be same as in Template '{1}'")
.format(self.stock_uom, template_uom)) .format(self.stock_uom, template_uom))
def validate_uom_conversion_factor(self): def validate_uom_conversion_factor(self):
if self.uoms: if self.uoms:
@@ -758,10 +749,13 @@ class Item(WebsiteGenerator):
d.conversion_factor = value d.conversion_factor = value
def validate_attributes(self): def validate_attributes(self):
if not (self.has_variants or self.variant_of):
return
if not self.variant_based_on: if not self.variant_based_on:
self.variant_based_on = 'Item Attribute' self.variant_based_on = 'Item Attribute'
if (self.has_variants or self.variant_of) and self.variant_based_on == 'Item Attribute': if self.variant_based_on == 'Item Attribute':
attributes = [] attributes = []
if not self.attributes: if not self.attributes:
frappe.throw(_("Attribute table is mandatory")) frappe.throw(_("Attribute table is mandatory"))
@@ -787,6 +781,11 @@ class Item(WebsiteGenerator):
validate_item_variant_attributes(self, args) validate_item_variant_attributes(self, args)
def validate_stock_for_has_batch_and_has_serial(self):
if self.stock_ledger_created():
for value in ["has_batch_no", "has_serial_no"]:
if frappe.db.get_value("Item", self.name, value) != self.get_value(value):
frappe.throw(_("Cannot change {0} as Stock Transaction for Item {1} exist.".format(value, self.name)))
def get_timeline_data(doctype, name): def get_timeline_data(doctype, name):
'''returns timeline data based on stock ledger entry''' '''returns timeline data based on stock ledger entry'''
@@ -866,18 +865,18 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
limit 1""", (item_code, cstr(doc_name)), as_dict=1) limit 1""", (item_code, cstr(doc_name)), as_dict=1)
purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date purchase_order_date = getdate(last_purchase_order and last_purchase_order[0].transaction_date
or "1900-01-01") or "1900-01-01")
purchase_receipt_date = getdate(last_purchase_receipt and purchase_receipt_date = getdate(last_purchase_receipt and
last_purchase_receipt[0].posting_date or "1900-01-01") last_purchase_receipt[0].posting_date or "1900-01-01")
if (purchase_order_date > purchase_receipt_date) or \ if (purchase_order_date > purchase_receipt_date) or \
(last_purchase_order and not last_purchase_receipt): (last_purchase_order and not last_purchase_receipt):
# use purchase order # use purchase order
last_purchase = last_purchase_order[0] last_purchase = last_purchase_order[0]
purchase_date = purchase_order_date purchase_date = purchase_order_date
elif (purchase_receipt_date > purchase_order_date) or \ elif (purchase_receipt_date > purchase_order_date) or \
(last_purchase_receipt and not last_purchase_order): (last_purchase_receipt and not last_purchase_order):
# use purchase receipt # use purchase receipt
last_purchase = last_purchase_receipt[0] last_purchase = last_purchase_receipt[0]
purchase_date = purchase_receipt_date purchase_date = purchase_receipt_date
@@ -907,7 +906,7 @@ def invalidate_cache_for_item(doc):
invalidate_cache_for(doc, doc.item_group) invalidate_cache_for(doc, doc.item_group)
website_item_groups = list(set((doc.get("old_website_item_groups") or []) website_item_groups = list(set((doc.get("old_website_item_groups") or [])
+ [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group])) + [d.item_group for d in doc.get({"doctype": "Website Item Group"}) if d.item_group]))
for item_group in website_item_groups: for item_group in website_item_groups:
invalidate_cache_for(doc, item_group) invalidate_cache_for(doc, item_group)
@@ -922,7 +921,7 @@ def check_stock_uom_with_bin(item, stock_uom):
matched = True matched = True
ref_uom = frappe.db.get_value("Stock Ledger Entry", ref_uom = frappe.db.get_value("Stock Ledger Entry",
{"item_code": item}, "stock_uom") {"item_code": item}, "stock_uom")
if ref_uom: if ref_uom:
if cstr(ref_uom) != cstr(stock_uom): if cstr(ref_uom) != cstr(stock_uom):
@@ -931,7 +930,7 @@ def check_stock_uom_with_bin(item, stock_uom):
bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1) bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1)
for bin in bin_list: for bin in bin_list:
if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0
or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom): or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom):
matched = False matched = False
break break

View File

@@ -6,7 +6,8 @@
"item_attribute_values": [ "item_attribute_values": [
{"attribute_value": "Small", "abbr": "S"}, {"attribute_value": "Small", "abbr": "S"},
{"attribute_value": "Medium", "abbr": "M"}, {"attribute_value": "Medium", "abbr": "M"},
{"attribute_value": "Large", "abbr": "L"} {"attribute_value": "Large", "abbr": "L"},
{"attribute_value": "Extra Small", "abbr": "XSL"}
] ]
}, },
{ {

View File

@@ -51,6 +51,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "If blank, parent Warehouse Account or company default will be considered",
"fieldname": "warehouse_name", "fieldname": "warehouse_name",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -870,7 +871,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-29 06:26:48.647225", "modified": "2018-08-29 06:26:49.647225",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Warehouse", "name": "Warehouse",

View File

@@ -606,28 +606,39 @@ def get_pos_profile_item_details(company, args, pos_profile=None, update_data=Fa
@frappe.whitelist() @frappe.whitelist()
def get_pos_profile(company, pos_profile=None, user=None): def get_pos_profile(company, pos_profile=None, user=None):
if pos_profile: if pos_profile: return frappe.get_cached_doc('POS Profile', pos_profile)
return frappe.get_cached_doc('POS Profile', pos_profile)
if not user: if not user:
user = frappe.session['user'] user = frappe.session['user']
condition = "pfu.user = %(user)s AND pfu.default=1"
if user and company:
condition = "pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1"
pos_profile = frappe.db.sql("""SELECT pf.* pos_profile = frappe.db.sql("""SELECT pf.*
FROM FROM
`tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu `tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu
ON ON
pf.name = pfu.parent pf.name = pfu.parent
WHERE WHERE
( {cond} AND pf.disabled = 0
(pfu.user = %(user)s AND pf.company = %(company)s AND pfu.default=1) """.format(cond = condition), {
OR (pfu.user = %(user)s AND pfu.default=1)
OR (ifnull(pfu.user, '') = '' AND pf.company = %(company)s)
) AND pf.disabled = 0
""", {
'user': user, 'user': user,
'company': company 'company': company
}, as_dict=1) }, as_dict=1)
if not pos_profile and company:
pos_profile = frappe.db.sql("""SELECT pf.*
FROM
`tabPOS Profile` pf LEFT JOIN `tabPOS Profile User` pfu
ON
pf.name = pfu.parent
WHERE
pf.company = %(company)s AND pf.disabled = 0
""", {
'company': company
}, as_dict=1)
return pos_profile and pos_profile[0] or None return pos_profile and pos_profile[0] or None
def get_serial_nos_by_fifo(args, sales_order=None): def get_serial_nos_by_fifo(args, sales_order=None):

View File

@@ -22,12 +22,8 @@ def execute(filters=None):
for sle in sl_entries: for sle in sl_entries:
item_detail = item_details[sle.item_code] item_detail = item_details[sle.item_code]
data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group, sle.update(item_detail)
item_detail.brand, item_detail.description, sle.warehouse, data.append(sle)
item_detail.stock_uom, sle.actual_qty, sle.qty_after_transaction,
(sle.incoming_rate if sle.actual_qty > 0 else 0.0),
sle.valuation_rate, sle.stock_value, sle.voucher_type, sle.voucher_no,
sle.batch_no, sle.serial_no, sle.project, sle.company])
if include_uom: if include_uom:
conversion_factors.append(item_detail.conversion_factor) conversion_factors.append(item_detail.conversion_factor)

View File

@@ -60,7 +60,7 @@
{{doc.terms}} {{doc.terms}}
</div> </div>
<div class="cart-link"> <div class="cart-link">
<a href="#" onclick="show_terms();return false;">*{{ __("Terms and Conditions") }}</a> <a href="#" onclick="show_terms();return false;">*{{ _("Terms and Conditions") }}</a>
</div> </div>
{% endif %} {% endif %}