Merge branch 'version-11-hotfix' into version-11

This commit is contained in:
Sahil Khan
2019-08-13 14:41:58 +05:30
22 changed files with 174 additions and 119 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.53' __version__ = '11.1.54'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

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

View File

@@ -168,38 +168,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "Open\nClosed",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@@ -273,7 +241,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-04-13 19:14:47.593753", "modified": "2019-08-01 19:14:47.593753",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounting Period", "name": "Accounting Period",

View File

@@ -4,8 +4,10 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe import _
class OverlapError(frappe.ValidationError): pass
class AccountingPeriod(Document): class AccountingPeriod(Document):
def validate(self): def validate(self):
@@ -34,12 +36,13 @@ class AccountingPeriod(Document):
}, as_dict=True) }, as_dict=True)
if len(existing_accounting_period) > 0: if len(existing_accounting_period) > 0:
frappe.throw(_("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))) frappe.throw(_("Accounting Period overlaps with {0}")
.format(existing_accounting_period[0].get("name")), OverlapError)
def get_doctypes_for_closing(self): def get_doctypes_for_closing(self):
docs_for_closing = [] docs_for_closing = []
#if not self.closed_documents or len(self.closed_documents) == 0: doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"] "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes] closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
for closed_doctype in closed_doctypes: for closed_doctype in closed_doctypes:
docs_for_closing.append(closed_doctype) docs_for_closing.append(closed_doctype)

View File

@@ -5,23 +5,42 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest import unittest
from frappe.utils import nowdate, add_months
from erpnext.accounts.general_ledger import ClosedAccountingPeriod
from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
# class TestAccountingPeriod(unittest.TestCase): class TestAccountingPeriod(unittest.TestCase):
# def test_overlap(self): def test_overlap(self):
# ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"}) ap1 = create_accounting_period(start_date = "2018-04-01",
# ap1.save() end_date = "2018-06-30", company = "Wind Power LLC")
# ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"}) ap1.save()
# self.assertRaises(frappe.OverlapError, accounting_period_2.save())
# ap2 = create_accounting_period(start_date = "2018-06-30",
# def tearDown(self): end_date = "2018-07-10", company = "Wind Power LLC", period_name = "Test Accounting Period 1")
# pass self.assertRaises(OverlapError, ap2.save)
#
# def test_accounting_period(self):
# def create_accounting_period(**args): ap1 = create_accounting_period(period_name = "Test Accounting Period 2")
# accounting_period = frappe.new_doc("Accounting Period") ap1.save()
# accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
# accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30) doc = create_sales_invoice(do_not_submit=1, cost_center = "_Test Company - _TC", warehouse = "Stores - _TC")
# accounting_period.company = args.company self.assertRaises(ClosedAccountingPeriod, doc.submit)
# accounting_period.period_name = "_Test_Period_Name_1"
# def tearDown(self):
# return accounting_period for d in frappe.get_all("Accounting Period"):
frappe.delete_doc("Accounting Period", d.name)
def create_accounting_period(**args):
args = frappe._dict(args)
accounting_period = frappe.new_doc("Accounting Period")
accounting_period.start_date = args.start_date or nowdate()
accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
accounting_period.company = args.company or "_Test Company"
accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
accounting_period.append("closed_documents", {
"document_type": 'Sales Invoice', "closed": 1
})
return accounting_period

View File

@@ -50,7 +50,7 @@ class BankTransaction(StatusUpdater):
if paid_amount and allocated_amount: if paid_amount and allocated_amount:
if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount): if flt(allocated_amount[0]["allocated_amount"]) > flt(paid_amount):
frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount)))) frappe.throw(_("The total allocated amount ({0}) is greated than the paid amount ({1}).".format(flt(allocated_amount[0]["allocated_amount"]), flt(paid_amount))))
elif flt(allocated_amount[0]["allocated_amount"]) == flt(paid_amount): else:
if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]: if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
self.clear_simple_entry(payment_entry) self.clear_simple_entry(payment_entry)

View File

@@ -78,6 +78,7 @@ class SalesInvoice(SellingController):
self.so_dn_required() self.so_dn_required()
self.validate_proj_cust() self.validate_proj_cust()
self.validate_pos_return()
self.validate_with_previous_doc() self.validate_with_previous_doc()
self.validate_uom_is_integer("stock_uom", "stock_qty") self.validate_uom_is_integer("stock_uom", "stock_qty")
self.validate_uom_is_integer("uom", "qty") self.validate_uom_is_integer("uom", "qty")
@@ -199,6 +200,16 @@ class SalesInvoice(SellingController):
if "Healthcare" in active_domains: if "Healthcare" in active_domains:
manage_invoice_submit_cancel(self, "on_submit") manage_invoice_submit_cancel(self, "on_submit")
def validate_pos_return(self):
if self.is_pos and self.is_return:
total_amount_in_payments = 0
for payment in self.payments:
total_amount_in_payments += payment.amount
if total_amount_in_payments < self.rounded_total:
frappe.throw(_("Total payments amount can't be greater than {}".format(-self.rounded_total)))
def validate_pos_paid_amount(self): def validate_pos_paid_amount(self):
if len(self.payments) == 0 and self.is_pos: if len(self.payments) == 0 and self.is_pos:
frappe.throw(_("At least one mode of payment is required for POS invoice.")) frappe.throw(_("At least one mode of payment is required for POS invoice."))

View File

@@ -9,11 +9,13 @@ from frappe.model.meta import get_field_precision
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
class ClosedAccountingPeriod(frappe.ValidationError): pass
class StockAccountInvalidTransaction(frappe.ValidationError): pass class StockAccountInvalidTransaction(frappe.ValidationError): pass
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False): def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
if gl_map: if gl_map:
if not cancel: if not cancel:
validate_accounting_period(gl_map)
gl_map = process_gl_map(gl_map, merge_entries) gl_map = process_gl_map(gl_map, merge_entries)
if gl_map and len(gl_map) > 1: if gl_map and len(gl_map) > 1:
save_entries(gl_map, adv_adj, update_outstanding, from_repost) save_entries(gl_map, adv_adj, update_outstanding, from_repost)
@@ -22,6 +24,27 @@ def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, upd
else: else:
delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding) delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
def validate_accounting_period(gl_map):
accounting_periods = frappe.db.sql(""" SELECT
ap.name as name
FROM
`tabAccounting Period` ap, `tabClosed Document` cd
WHERE
ap.name = cd.parent
AND ap.company = %(company)s
AND cd.closed = 1
AND cd.document_type = %(voucher_type)s
AND %(date)s between ap.start_date and ap.end_date
""", {
'date': gl_map[0].posting_date,
'company': gl_map[0].company,
'voucher_type': gl_map[0].voucher_type
}, as_dict=1)
if accounting_periods:
frappe.throw(_("You can't create accounting entries in the closed accounting period {0}")
.format(accounting_periods[0].name), ClosedAccountingPeriod)
def process_gl_map(gl_map, merge_entries=True): def process_gl_map(gl_map, merge_entries=True):
if merge_entries: if merge_entries:
gl_map = merge_similar_entries(gl_map) gl_map = merge_similar_entries(gl_map)

View File

@@ -4,7 +4,7 @@
{%- macro render_currency(df, doc) -%} {%- macro render_currency(df, doc) -%}
<div class="row {% if df.bold %}important{% endif %} data-field"> <div class="row {% if df.bold %}important{% endif %} data-field">
<div class="col-xs-{{ "9" if df.fieldtype=="Check" else "5" }} <div class="col-xs-{{ "9" if df.fieldtype=="Check" else "5" }}
{%- if doc._align_labels_right %} text-right{%- endif -%}"> {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _(df.label) }}</label> <label>{{ _(df.label) }}</label>
</div> </div>
<div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value"> <div class="col-xs-{{ "3" if df.fieldtype=="Check" else "7" }} value">
@@ -23,7 +23,7 @@
{%- for charge in data -%} {%- for charge in data -%}
{%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%} {%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
<div class="row"> <div class="row">
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}"> <div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ charge.get_formatted("description") }}</label></div> <label>{{ charge.get_formatted("description") }}</label></div>
<div class="col-xs-7 text-right"> <div class="col-xs-7 text-right">
{{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }} {{ frappe.utils.fmt_money((charge.tax_amount)|int|abs, currency=doc.currency) }}
@@ -103,8 +103,8 @@
{% for section in page %} {% for section in page %}
<div class="row section-break"> <div class="row section-break">
{% if section.columns.fields %} {% if section.columns.fields %}
{%- if doc._line_breaks and loop.index != 1 -%}<hr>{%- endif -%} {%- if doc.print_line_breaks and loop.index != 1 -%}<hr>{%- endif -%}
{%- if doc._show_section_headings and section.label and section.has_data -%} {%- if doc.print_section_headings and section.label and section.has_data -%}
<h4 class='col-sm-12'>{{ _(section.label) }}</h4> <h4 class='col-sm-12'>{{ _(section.label) }}</h4>
{% endif %} {% endif %}
{%- endif -%} {%- endif -%}

View File

@@ -472,7 +472,7 @@ def make_rm_stock_entry(purchase_order, rm_items):
'from_warehouse': rm_item_data["warehouse"], 'from_warehouse': rm_item_data["warehouse"],
'stock_uom': rm_item_data["stock_uom"], 'stock_uom': rm_item_data["stock_uom"],
'main_item_code': rm_item_data["item_code"], 'main_item_code': rm_item_data["item_code"],
'allow_alternative_item': item_wh[rm_item_code].get('allow_alternative_item') 'allow_alternative_item': item_wh.get(rm_item_code, {}).get('allow_alternative_item')
} }
} }
stock_entry.add_to_stock_entry_detail(items_dict) stock_entry.add_to_stock_entry_detail(items_dict)

View File

@@ -717,7 +717,7 @@ def get_items_from_bom(item_code, bom, exploded_item=1):
where where
t2.parent = t1.name and t1.item = %s t2.parent = t1.name and t1.item = %s
and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s and t1.docstatus = 1 and t1.is_active = 1 and t1.name = %s
and t2.item_code = t3.name and t3.is_stock_item = 1""".format(doctype), and t2.item_code = t3.name""".format(doctype),
(item_code, bom), as_dict=1) (item_code, bom), as_dict=1)
if not bom_items: if not bom_items:

View File

@@ -21,42 +21,45 @@ def get_list_context(context=None):
def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"): def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20, order_by="modified"):
user = frappe.session.user user = frappe.session.user
key = None ignore_permissions = False
if not filters: filters = [] if not filters: filters = []
if doctype == 'Supplier Quotation': if doctype == 'Supplier Quotation':
filters.append((doctype, "docstatus", "<", 2)) filters.append((doctype, 'docstatus', '<', 2))
else: else:
filters.append((doctype, "docstatus", "=", 1)) filters.append((doctype, 'docstatus', '=', 1))
if (user != "Guest" and is_website_user()) or doctype == 'Request for Quotation': if (user != 'Guest' and is_website_user()) or doctype == 'Request for Quotation':
parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype
# find party for this contact # find party for this contact
customers, suppliers = get_customers_suppliers(parties_doctype, user) customers, suppliers = get_customers_suppliers(parties_doctype, user)
if not customers and not suppliers: return [] if customers:
if doctype == 'Quotation':
key, parties = get_party_details(customers, suppliers) filters.append(('quotation_to', '=', 'Customer'))
filters.append(('party_name', 'in', customers))
if doctype == 'Request for Quotation': else:
return rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length) filters.append(('customer', 'in', customers))
elif suppliers:
filters.append((doctype, key, "in", parties)) filters.append(('supplier', 'in', suppliers))
if key:
return post_process(doctype, get_list_for_transactions(doctype, txt,
filters=filters, fields="name",limit_start=limit_start,
limit_page_length=limit_page_length,ignore_permissions=True,
order_by="modified desc"))
else: else:
return [] return []
return post_process(doctype, get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length, if doctype == 'Request for Quotation':
fields="name", order_by="modified desc")) parties = customers or suppliers
return rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length)
# Since customers and supplier do not have direct access to internal doctypes
ignore_permissions = True
transactions = get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length,
fields='name', ignore_permissions=ignore_permissions, order_by='modified desc')
return post_process(doctype, transactions)
def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length=20, def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_length=20,
ignore_permissions=False,fields=None, order_by=None): ignore_permissions=False, fields=None, order_by=None):
""" Get List of transactions like Invoices, Orders """ """ Get List of transactions like Invoices, Orders """
from frappe.www.list import get_list from frappe.www.list import get_list
meta = frappe.get_meta(doctype) meta = frappe.get_meta(doctype)
@@ -83,16 +86,6 @@ def get_list_for_transactions(doctype, txt, filters, limit_start, limit_page_len
return data return data
def get_party_details(customers, suppliers):
if customers:
key, parties = "customer", customers
elif suppliers:
key, parties = "supplier", suppliers
else:
key, parties = "customer", []
return key, parties
def rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length): def rfq_transaction_list(parties_doctype, doctype, parties, limit_start, limit_page_length):
data = frappe.db.sql("""select distinct parent as name, supplier from `tab{doctype}` data = frappe.db.sql("""select distinct parent as name, supplier from `tab{doctype}`
where supplier = '{supplier}' and docstatus=1 order by modified desc limit {start}, {len}""". where supplier = '{supplier}' and docstatus=1 order by modified desc limit {start}, {len}""".
@@ -159,7 +152,7 @@ def has_website_permission(doc, ptype, user, verbose=False):
doctype = doc.doctype doctype = doc.doctype
customers, suppliers = get_customers_suppliers(doctype, user) customers, suppliers = get_customers_suppliers(doctype, user)
if customers: if customers:
return frappe.db.exists(doctype, filters=get_customer_filter(doc, customers)) return frappe.db.exists(doctype, get_customer_filter(doc, customers))
elif suppliers: elif suppliers:
fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier' fieldname = 'suppliers' if doctype == 'Request for Quotation' else 'supplier'
return frappe.db.exists(doctype, filters={ return frappe.db.exists(doctype, filters={
@@ -175,7 +168,7 @@ def get_customer_filter(doc, customers):
filters.name = doc.name filters.name = doc.name
filters[get_customer_field_name(doctype)] = ['in', customers] filters[get_customer_field_name(doctype)] = ['in', customers]
if doctype == 'Quotation': if doctype == 'Quotation':
filters.party_type = 'Customer' filters.quotation_to = 'Customer'
return filters return filters
def get_customer_field_name(doctype): def get_customer_field_name(doctype):

View File

@@ -1460,7 +1460,7 @@
"has_web_view": 0, "has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"icon": "fa fa-info-sign", "icon": "fa fa-info-circle",
"idx": 195, "idx": 195,
"image_view": 0, "image_view": 0,
"in_create": 0, "in_create": 0,

View File

@@ -20,6 +20,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "status", "fieldname": "status",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 1, "hidden": 1,
@@ -54,6 +55,7 @@
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "eval:doc.client_id && doc.client_secret && doc.redirect_url", "collapsible_depends_on": "eval:doc.client_id && doc.client_secret && doc.redirect_url",
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "application_settings", "fieldname": "application_settings",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -87,6 +89,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "client_id", "fieldname": "client_id",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -120,6 +123,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "redirect_url", "fieldname": "redirect_url",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -153,6 +157,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer", "default": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
"fetch_if_empty": 0,
"fieldname": "token_endpoint", "fieldname": "token_endpoint",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -185,6 +190,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "application_column_break", "fieldname": "application_column_break",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -217,6 +223,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "", "default": "",
"fetch_if_empty": 0,
"fieldname": "client_secret", "fieldname": "client_secret",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -250,6 +257,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "com.intuit.quickbooks.accounting", "default": "com.intuit.quickbooks.accounting",
"fetch_if_empty": 0,
"fieldname": "scope", "fieldname": "scope",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -284,6 +292,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "https://quickbooks.api.intuit.com/v3", "default": "https://quickbooks.api.intuit.com/v3",
"fetch_if_empty": 0,
"fieldname": "api_endpoint", "fieldname": "api_endpoint",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -316,6 +325,7 @@
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "authorization_settings", "fieldname": "authorization_settings",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@@ -349,6 +359,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "https://appcenter.intuit.com/connect/oauth2", "default": "https://appcenter.intuit.com/connect/oauth2",
"fetch_if_empty": 0,
"fieldname": "authorization_endpoint", "fieldname": "authorization_endpoint",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -381,6 +392,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "refresh_token", "fieldname": "refresh_token",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 1, "hidden": 1,
@@ -413,6 +425,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "code", "fieldname": "code",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -445,6 +458,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "authorization_column_break", "fieldname": "authorization_column_break",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -476,6 +490,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "authorization_url", "fieldname": "authorization_url",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0, "hidden": 0,
@@ -508,6 +523,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "access_token", "fieldname": "access_token",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 1, "hidden": 1,
@@ -540,6 +556,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "quickbooks_company_id", "fieldname": "quickbooks_company_id",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
@@ -572,6 +589,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "company_settings", "fieldname": "company_settings",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 1, "hidden": 1,
@@ -604,6 +622,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,
@@ -637,6 +656,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_shipping_account", "fieldname": "default_shipping_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -670,6 +690,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_warehouse", "fieldname": "default_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -703,6 +724,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "company_column_break", "fieldname": "company_column_break",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
@@ -734,6 +756,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "default_cost_center", "fieldname": "default_cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -767,6 +790,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_if_empty": 0,
"fieldname": "undeposited_funds_account", "fieldname": "undeposited_funds_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
@@ -804,7 +828,7 @@
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-17 03:12:53.506229", "modified": "2019-08-07 05:53:00.920316",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "ERPNext Integrations", "module": "ERPNext Integrations",
"name": "QuickBooks Migrator", "name": "QuickBooks Migrator",
@@ -834,7 +858,7 @@
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 1, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 0, "track_changes": 0,

View File

@@ -188,8 +188,7 @@ frappe.ui.form.on("Expense Claim", {
frappe.set_route("query-report", "General Ledger"); frappe.set_route("query-report", "General Ledger");
}, __("View")); }, __("View"));
} }
if (frm.doc.docstatus===1 && !cint(frm.doc.is_paid)
if (frm.doc.docstatus===1 && !cint(frm.doc.is_paid) && cint(frm.doc.grand_total) > 0
&& (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount)) && (cint(frm.doc.total_amount_reimbursed) < cint(frm.doc.total_sanctioned_amount))
&& frappe.model.can_create("Payment Entry")) { && frappe.model.can_create("Payment Entry")) {
frm.add_custom_button(__('Payment'), frm.add_custom_button(__('Payment'),

View File

@@ -391,7 +391,8 @@ erpnext.buying.get_items_from_product_bundle = function(frm) {
company: frm.doc.company, company: frm.doc.company,
is_subcontracted: frm.doc.is_subcontracted, is_subcontracted: frm.doc.is_subcontracted,
transaction_date: frm.doc.transaction_date || frm.doc.posting_date, transaction_date: frm.doc.transaction_date || frm.doc.posting_date,
ignore_pricing_rule: frm.doc.ignore_pricing_rule ignore_pricing_rule: frm.doc.ignore_pricing_rule,
doctype: frm.doc.doctype
} }
}, },
freeze: true, freeze: true,

View File

@@ -129,6 +129,8 @@ def download_zip(files, output_filename):
def get_invoice_summary(items, taxes): def get_invoice_summary(items, taxes):
summary_data = frappe._dict() summary_data = frappe._dict()
applied_tax_row_ids = []
for tax in taxes: for tax in taxes:
#Include only VAT charges. #Include only VAT charges.
if tax.charge_type == "Actual": if tax.charge_type == "Actual":
@@ -153,7 +155,9 @@ def get_invoice_summary(items, taxes):
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={tax.account_head: tax.rate}, item_tax_rate={tax.account_head: tax.rate},
charges=True charges=True,
type="Actual",
tax_row_name=tax.name
) )
) )
@@ -165,13 +169,21 @@ def get_invoice_summary(items, taxes):
item_tax_rate = json.loads(item.item_tax_rate) item_tax_rate = json.loads(item.item_tax_rate)
if item_tax_rate and tax.account_head in item_tax_rate: if item_tax_rate and tax.account_head in item_tax_rate:
if (item.get("tax_row_name")
and item.get("tax_row_name") in applied_tax_row_ids):
continue
key = cstr(item_tax_rate[tax.account_head]) key = cstr(item_tax_rate[tax.account_head])
if key not in summary_data: if key not in summary_data:
summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0, summary_data.setdefault(key, {"tax_amount": 0.0, "taxable_amount": 0.0,
"tax_exemption_reason": "", "tax_exemption_law": ""}) "tax_exemption_reason": "", "tax_exemption_law": ""})
if item.get("type") and item.get("type") == "Actual":
applied_tax_row_ids.append(item.get("tax_row_name"))
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":
summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason
summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law

View File

@@ -3,7 +3,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
import urllib
import copy import copy
from frappe.utils import nowdate, cint, cstr from frappe.utils import nowdate, cint, cstr
from frappe.utils.nestedset import NestedSet from frappe.utils.nestedset import NestedSet
@@ -12,6 +11,7 @@ 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 six.moves.urllib.parse import quote
class ItemGroup(NestedSet, WebsiteGenerator): class ItemGroup(NestedSet, WebsiteGenerator):
nsm_parent_field = 'parent_item_group' nsm_parent_field = 'parent_item_group'
@@ -166,7 +166,7 @@ def get_item_for_list_in_html(context):
# add missing absolute link in files # add missing absolute link in files
# user may forget it during upload # user may forget it during upload
if (context.get("website_image") or "").startswith("files/"): if (context.get("website_image") or "").startswith("files/"):
context["website_image"] = "/" + urllib.quote(context["website_image"]) context["website_image"] = "/" + quote(context["website_image"])
context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings', context["show_availability_status"] = cint(frappe.db.get_single_value('Products Settings',
'show_availability_status')) 'show_availability_status'))

View File

@@ -171,7 +171,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
}); });
if(!from_sales_invoice) { if(!from_sales_invoice) {
this.frm.add_custom_button(__('Invoice'), function() { me.make_sales_invoice() }, this.frm.add_custom_button(__('Sales Invoice'), function() { me.make_sales_invoice() },
__("Make")); __("Make"));
} }
} }

View File

@@ -5,8 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.utils import formatdate from frappe.utils import formatdate
from erpnext.controllers.website_list_for_contact import (get_customers_suppliers, from erpnext.controllers.website_list_for_contact import get_customers_suppliers
get_party_details)
def get_context(context): def get_context(context):
context.no_cache = 1 context.no_cache = 1
@@ -23,8 +22,8 @@ def get_supplier():
doctype = frappe.form_dict.doctype doctype = frappe.form_dict.doctype
parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype parties_doctype = 'Request for Quotation Supplier' if doctype == 'Request for Quotation' else doctype
customers, suppliers = get_customers_suppliers(parties_doctype, frappe.session.user) customers, suppliers = get_customers_suppliers(parties_doctype, frappe.session.user)
key, parties = get_party_details(customers, suppliers)
return parties[0] if key == 'supplier' else '' return suppliers[0] if suppliers else ''
def check_supplier_has_docname_access(supplier): def check_supplier_has_docname_access(supplier):
status = True status = True

View File

@@ -1,7 +1,7 @@
{%- macro render_discount_amount(doc) -%} {%- macro render_discount_amount(doc) -%}
{%- if doc.discount_amount -%} {%- if doc.discount_amount -%}
<div class="row"> <div class="row">
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}"> <div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _(doc.meta.get_label('discount_amount')) }}</label></div> <label>{{ _(doc.meta.get_label('discount_amount')) }}</label></div>
<div class="col-xs-7 text-right"> <div class="col-xs-7 text-right">
- {{ doc.get_formatted("discount_amount", doc) }} - {{ doc.get_formatted("discount_amount", doc) }}
@@ -19,7 +19,7 @@
{%- for charge in data -%} {%- for charge in data -%}
{%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%} {%- if (charge.tax_amount or doc.flags.print_taxes_with_zero_amount) and (not charge.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) -%}
<div class="row"> <div class="row">
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}"> <div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ charge.get_formatted("description") }}</label></div> <label>{{ charge.get_formatted("description") }}</label></div>
<div class="col-xs-7 text-right"> <div class="col-xs-7 text-right">
{{ frappe.format_value(frappe.utils.flt(charge.tax_amount), {{ frappe.format_value(frappe.utils.flt(charge.tax_amount),

View File

@@ -1,12 +1,12 @@
<div class="row"> <div class="row">
{% if doc.flags.show_inclusive_tax_in_print %} {% if doc.flags.show_inclusive_tax_in_print %}
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}"> <div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _("Total (Without Tax)") }}</label></div> <label>{{ _("Total (Without Tax)") }}</label></div>
<div class="col-xs-7 text-right"> <div class="col-xs-7 text-right">
{{ doc.get_formatted("net_total", doc) }} {{ doc.get_formatted("net_total", doc) }}
</div> </div>
{% else %} {% else %}
<div class="col-xs-5 {%- if doc._align_labels_right %} text-right{%- endif -%}"> <div class="col-xs-5 {%- if doc.align_labels_right %} text-right{%- endif -%}">
<label>{{ _(doc.meta.get_label('total')) }}</label></div> <label>{{ _(doc.meta.get_label('total')) }}</label></div>
<div class="col-xs-7 text-right"> <div class="col-xs-7 text-right">
{{ doc.get_formatted("total", doc) }} {{ doc.get_formatted("total", doc) }}