Merge branch 'version-12-hotfix' of https://github.com/frappe/erpnext into contacts-ref

This commit is contained in:
Himanshu Warekar
2019-08-20 20:38:18 +05:30
19 changed files with 207 additions and 379 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__ = '12.0.5' __version__ = '12.0.7'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@@ -624,7 +624,7 @@ def get_outstanding_reference_documents(args):
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
if not data: if not data:
frappe.msgprint(_("No outstanding invoices found for the {0} <b>{1}</b>.") frappe.msgprint(_("No outstanding invoices found for the {0} <b>{1}</b> which qualify the filters you have specified")
.format(args.get("party_type").lower(), args.get("party"))) .format(args.get("party_type").lower(), args.get("party")))
return data return data

View File

@@ -66,6 +66,7 @@ frappe.ui.form.on('Payment Order', {
get_query_filters: { get_query_filters: {
bank: frm.doc.bank, bank: frm.doc.bank,
docstatus: 1, docstatus: 1,
payment_type: ("!=", "Receive"),
bank_account: frm.doc.company_bank_account, bank_account: frm.doc.company_bank_account,
paid_from: frm.doc.account, paid_from: frm.doc.account,
payment_order_status: ["=", "Initiated"], payment_order_status: ["=", "Initiated"],

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

@@ -119,19 +119,11 @@ def get_gl_entries(filters):
select_fields = """, debit, credit, debit_in_account_currency, select_fields = """, debit, credit, debit_in_account_currency,
credit_in_account_currency """ credit_in_account_currency """
group_by_statement = ''
order_by_statement = "order by posting_date, account" order_by_statement = "order by posting_date, account"
if filters.get("group_by") == _("Group by Voucher"): if filters.get("group_by") == _("Group by Voucher"):
order_by_statement = "order by posting_date, voucher_type, voucher_no" order_by_statement = "order by posting_date, voucher_type, voucher_no"
if filters.get("group_by") == _("Group by Voucher (Consolidated)"):
group_by_statement = "group by voucher_type, voucher_no, account, cost_center"
select_fields = """, sum(debit) as debit, sum(credit) as credit,
sum(debit_in_account_currency) as debit_in_account_currency,
sum(credit_in_account_currency) as credit_in_account_currency"""
if filters.get("include_default_book_entries"): if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Company", filters['company_fb'] = frappe.db.get_value("Company",
filters.get("company"), 'default_finance_book') filters.get("company"), 'default_finance_book')
@@ -144,11 +136,10 @@ def get_gl_entries(filters):
against_voucher_type, against_voucher, account_currency, against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields} remarks, against, is_opening {select_fields}
from `tabGL Entry` from `tabGL Entry`
where company=%(company)s {conditions} {group_by_statement} where company=%(company)s {conditions}
{order_by_statement} {order_by_statement}
""".format( """.format(
select_fields=select_fields, conditions=get_conditions(filters), select_fields=select_fields, conditions=get_conditions(filters),
group_by_statement=group_by_statement,
order_by_statement=order_by_statement order_by_statement=order_by_statement
), ),
filters, as_dict=1) filters, as_dict=1)
@@ -185,7 +176,8 @@ def get_conditions(filters):
if not (filters.get("account") or filters.get("party") or if not (filters.get("account") or filters.get("party") or
filters.get("group_by") in ["Group by Account", "Group by Party"]): filters.get("group_by") in ["Group by Account", "Group by Party"]):
conditions.append("posting_date >=%(from_date)s") conditions.append("posting_date >=%(from_date)s")
conditions.append("posting_date <=%(to_date)s")
conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')")
if filters.get("project"): if filters.get("project"):
conditions.append("project in %(project)s") conditions.append("project in %(project)s")
@@ -286,6 +278,7 @@ def initialize_gle_map(gl_entries, filters):
def get_accountwise_gle(filters, gl_entries, gle_map): def get_accountwise_gle(filters, gl_entries, gle_map):
totals = get_totals_dict() totals = get_totals_dict()
entries = [] entries = []
consolidated_gle = OrderedDict()
group_by = group_by_field(filters.get('group_by')) group_by = group_by_field(filters.get('group_by'))
def update_value_in_dict(data, key, gle): def update_value_in_dict(data, key, gle):
@@ -310,12 +303,20 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
update_value_in_dict(totals, 'total', gle) update_value_in_dict(totals, 'total', gle)
if filters.get("group_by") != _('Group by Voucher (Consolidated)'): if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
gle_map[gle.get(group_by)].entries.append(gle) gle_map[gle.get(group_by)].entries.append(gle)
else: elif filters.get("group_by") == _('Group by Voucher (Consolidated)'):
entries.append(gle) key = (gle.get("voucher_type"), gle.get("voucher_no"),
gle.get("account"), gle.get("cost_center"))
if key not in consolidated_gle:
consolidated_gle.setdefault(key, gle)
else:
update_value_in_dict(consolidated_gle, key, gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle) update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle) update_value_in_dict(totals, 'closing', gle)
for key, value in consolidated_gle.items():
entries.append(value)
return totals, entries return totals, entries
def get_result_as_list(data, filters): def get_result_as_list(data, filters):

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

@@ -596,6 +596,7 @@ erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
erpnext.patches.v12_0.move_target_distribution_from_parent_to_child erpnext.patches.v12_0.move_target_distribution_from_parent_to_child
erpnext.patches.v12_0.stock_entry_enhancements erpnext.patches.v12_0.stock_entry_enhancements
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019 erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019
erpnext.patches.v12_0.make_item_manufacturer
erpnext.patches.v12_0.move_item_tax_to_item_tax_template erpnext.patches.v12_0.move_item_tax_to_item_tax_template
erpnext.patches.v11_1.set_variant_based_on erpnext.patches.v11_1.set_variant_based_on
erpnext.patches.v11_1.woocommerce_set_creation_user erpnext.patches.v11_1.woocommerce_set_creation_user
@@ -606,7 +607,6 @@ erpnext.patches.v11_1.delete_scheduling_tool
erpnext.patches.v12_0.rename_tolerance_fields erpnext.patches.v12_0.rename_tolerance_fields
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019 erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
execute:frappe.delete_doc_if_exists("Page", "support-analytics") execute:frappe.delete_doc_if_exists("Page", "support-analytics")
erpnext.patches.v12_0.make_item_manufacturer
erpnext.patches.v12_0.remove_patient_medical_record_page erpnext.patches.v12_0.remove_patient_medical_record_page
erpnext.patches.v11_1.move_customer_lead_to_dynamic_column erpnext.patches.v11_1.move_customer_lead_to_dynamic_column
erpnext.patches.v11_1.set_default_action_for_quality_inspection erpnext.patches.v11_1.set_default_action_for_quality_inspection

View File

@@ -5,67 +5,67 @@ from __future__ import unicode_literals
import frappe import frappe
parentfield = { parentfield = {
'item_code': 'items', 'item_code': 'items',
'item_group': 'item_groups', 'item_group': 'item_groups',
'brand': 'brands' 'brand': 'brands'
} }
def execute(): def execute():
if not frappe.get_all('Pricing Rule', limit=1): if not frappe.get_all('Pricing Rule', limit=1):
return return
frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail') frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail')
doctypes = {'Supplier Quotation': 'buying', 'Purchase Order': 'buying', 'Purchase Invoice': 'accounts', doctypes = {'Supplier Quotation': 'buying', 'Purchase Order': 'buying', 'Purchase Invoice': 'accounts',
'Purchase Receipt': 'stock', 'Quotation': 'selling', 'Sales Order': 'selling', 'Purchase Receipt': 'stock', 'Quotation': 'selling', 'Sales Order': 'selling',
'Sales Invoice': 'accounts', 'Delivery Note': 'stock'} 'Sales Invoice': 'accounts', 'Delivery Note': 'stock'}
for doctype, module in doctypes.items(): for doctype, module in doctypes.items():
frappe.reload_doc(module, 'doctype', frappe.scrub(doctype)) frappe.reload_doc(module, 'doctype', frappe.scrub(doctype))
child_doc = frappe.scrub(doctype) + '_item' child_doc = frappe.scrub(doctype) + '_item'
frappe.reload_doc(module, 'doctype', child_doc) frappe.reload_doc(module, 'doctype', child_doc, force=True)
child_doctype = doctype + ' Item' child_doctype = doctype + ' Item'
frappe.db.sql(""" UPDATE `tab{child_doctype}` SET pricing_rules = pricing_rule frappe.db.sql(""" UPDATE `tab{child_doctype}` SET pricing_rules = pricing_rule
WHERE docstatus < 2 and pricing_rule is not null and pricing_rule != '' WHERE docstatus < 2 and pricing_rule is not null and pricing_rule != ''
""".format(child_doctype= child_doctype)) """.format(child_doctype= child_doctype))
data = frappe.db.sql(""" SELECT pricing_rule, name, parent, data = frappe.db.sql(""" SELECT pricing_rule, name, parent,
parenttype, creation, modified, docstatus, modified_by, owner, name parenttype, creation, modified, docstatus, modified_by, owner, name
FROM `tab{child_doc}` where docstatus < 2 and pricing_rule is not null FROM `tab{child_doc}` where docstatus < 2 and pricing_rule is not null
and pricing_rule != ''""".format(child_doc=child_doctype), as_dict=1) and pricing_rule != ''""".format(child_doc=child_doctype), as_dict=1)
values = [] values = []
for d in data: for d in data:
values.append((d.pricing_rule, d.name, d.parent, 'pricing_rules', d.parenttype, values.append((d.pricing_rule, d.name, d.parent, 'pricing_rules', d.parenttype,
d.creation, d.modified, d.docstatus, d.modified_by, d.owner, frappe.generate_hash("", 10))) d.creation, d.modified, d.docstatus, d.modified_by, d.owner, frappe.generate_hash("", 10)))
if values: if values:
frappe.db.sql(""" INSERT INTO frappe.db.sql(""" INSERT INTO
`tabPricing Rule Detail` (`pricing_rule`, `child_docname`, `parent`, `parentfield`, `parenttype`, `tabPricing Rule Detail` (`pricing_rule`, `child_docname`, `parent`, `parentfield`, `parenttype`,
`creation`, `modified`, `docstatus`, `modified_by`, `owner`, `name`) `creation`, `modified`, `docstatus`, `modified_by`, `owner`, `name`)
VALUES {values} """.format(values=', '.join(['%s'] * len(values))), tuple(values)) VALUES {values} """.format(values=', '.join(['%s'] * len(values))), tuple(values))
frappe.reload_doc('accounts', 'doctype', 'pricing_rule') frappe.reload_doc('accounts', 'doctype', 'pricing_rule')
for doctype, apply_on in {'Pricing Rule Item Code': 'Item Code', for doctype, apply_on in {'Pricing Rule Item Code': 'Item Code',
'Pricing Rule Item Group': 'Item Group', 'Pricing Rule Brand': 'Brand'}.items(): 'Pricing Rule Item Group': 'Item Group', 'Pricing Rule Brand': 'Brand'}.items():
frappe.reload_doc('accounts', 'doctype', frappe.scrub(doctype)) frappe.reload_doc('accounts', 'doctype', frappe.scrub(doctype))
field = frappe.scrub(apply_on) field = frappe.scrub(apply_on)
data = frappe.get_all('Pricing Rule', fields=[field, "name", "creation", "modified", data = frappe.get_all('Pricing Rule', fields=[field, "name", "creation", "modified",
"owner", "modified_by"], filters= {'apply_on': apply_on}) "owner", "modified_by"], filters= {'apply_on': apply_on})
values = [] values = []
for d in data: for d in data:
values.append((d.get(field), d.name, parentfield.get(field), 'Pricing Rule', values.append((d.get(field), d.name, parentfield.get(field), 'Pricing Rule',
d.creation, d.modified, d.owner, d.modified_by, frappe.generate_hash("", 10))) d.creation, d.modified, d.owner, d.modified_by, frappe.generate_hash("", 10)))
if values: if values:
frappe.db.sql(""" INSERT INTO frappe.db.sql(""" INSERT INTO
`tab{doctype}` ({field}, parent, parentfield, parenttype, creation, modified, `tab{doctype}` ({field}, parent, parentfield, parenttype, creation, modified,
owner, modified_by, name) owner, modified_by, name)
VALUES {values} """.format(doctype=doctype, VALUES {values} """.format(doctype=doctype,
field=field, values=', '.join(['%s'] * len(values))), tuple(values)) field=field, values=', '.join(['%s'] * len(values))), tuple(values))

View File

@@ -2,7 +2,7 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on('GSTR 3B Report', { frappe.ui.form.on('GSTR 3B Report', {
refresh : function(frm){ refresh : function(frm) {
if(!frm.is_new()) { if(!frm.is_new()) {
frm.set_intro(__("Please save the report again to rebuild or update")); frm.set_intro(__("Please save the report again to rebuild or update"));
frm.add_custom_button(__('Download JSON'), function() { frm.add_custom_button(__('Download JSON'), function() {
@@ -39,9 +39,13 @@ frappe.ui.form.on('GSTR 3B Report', {
}); });
}); });
} }
let current_year = new Date().getFullYear();
let options = [current_year, current_year-1, current_year-2];
frm.set_df_property('year', 'options', options);
}, },
setup: function(frm){ setup: function(frm) {
frm.set_query('company_address', function(doc) { frm.set_query('company_address', function(doc) {
if(!doc.company) { if(!doc.company) {
frappe.throw(__('Please set Company')); frappe.throw(__('Please set Company'));

View File

@@ -1,259 +1,73 @@
{ {
"allow_copy": 0, "autoname": "format:GSTR3B-{month}-{year}-{company_address}",
"allow_events_in_timeline": 0, "creation": "2019-02-04 11:35:55.964639",
"allow_guest_to_view": 0, "doctype": "DocType",
"allow_import": 0, "editable_grid": 1,
"allow_rename": 0, "engine": "InnoDB",
"autoname": "format:GSTR3B-{month}-{year}-{company_address}", "field_order": [
"beta": 0, "company",
"creation": "2019-02-04 11:35:55.964639", "company_address",
"custom": 0, "year",
"docstatus": 0, "month",
"doctype": "DocType", "json_output",
"document_type": "", "missing_field_invoices"
"editable_grid": 1, ],
"engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "company",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "label": "Company",
"bold": 0, "options": "Company"
"collapsible": 0, },
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "company_address",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "label": "Company Address",
"bold": 0, "options": "Address"
"collapsible": 0, },
"columns": 0,
"fieldname": "company_address",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company Address",
"length": 0,
"no_copy": 0,
"options": "Address",
"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, "fieldname": "year",
"allow_in_quick_entry": 0, "fieldtype": "Select",
"allow_on_submit": 0, "label": "Year"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "year",
"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": "Year",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "month",
"allow_in_quick_entry": 0, "fieldtype": "Select",
"allow_on_submit": 0, "label": "Month",
"bold": 0, "options": "January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember"
"collapsible": 0, },
"columns": 0,
"fieldname": "month",
"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": "Month",
"length": 0,
"no_copy": 0,
"options": "January\nFebruary\nMarch\nApril\nMay\nJune\nJuly\nAugust\nSeptember\nOctober\nNovember\nDecember",
"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, "fieldname": "json_output",
"allow_in_quick_entry": 0, "fieldtype": "Code",
"allow_on_submit": 0, "label": "JSON Output"
"bold": 0, },
"collapsible": 0,
"columns": 0,
"fieldname": "json_output",
"fieldtype": "Code",
"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": "JSON Output",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "fieldname": "missing_field_invoices",
"allow_in_quick_entry": 0, "fieldtype": "Small Text",
"allow_on_submit": 0, "label": "Invoices with no Place Of Supply",
"bold": 0, "read_only": 1
"collapsible": 0,
"columns": 0,
"fieldname": "missing_field_invoices",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Invoices with no Place Of Supply",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
} }
], ],
"has_web_view": 0, "modified": "2019-08-10 22:30:26.727038",
"hide_heading": 0, "modified_by": "Administrator",
"hide_toolbar": 0, "module": "Regional",
"idx": 0, "name": "GSTR 3B Report",
"image_view": 0, "owner": "Administrator",
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-03-04 10:04:44.767655",
"modified_by": "Administrator",
"module": "Regional",
"name": "GSTR 3B Report",
"name_case": "",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"cancel": 0, "delete": 1,
"create": 1, "email": 1,
"delete": 1, "export": 1,
"email": 1, "print": 1,
"export": 1, "read": 1,
"if_owner": 0, "report": 1,
"import": 0, "role": "System Manager",
"permlevel": 0, "share": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "sort_field": "modified",
"read_only": 0, "sort_order": "DESC",
"read_only_onload": 0, "track_changes": 1
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
} }

View File

@@ -329,28 +329,29 @@ class GSTR3BReport(Document):
d.gst_category, [] d.gst_category, []
) )
if state_number != d.place_of_supply.split("-")[0]: if d.place_of_supply:
inter_state_supply_details[d.gst_category].append({ if state_number != d.place_of_supply.split("-")[0]:
"pos": d.place_of_supply, inter_state_supply_details[d.gst_category].append({
"txval": flt(d.total, 2), "pos": d.place_of_supply.split("-")[0],
"iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2) "txval": flt(d.total, 2),
}) "iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2)
else: })
osup_det = self.report_dict["sup_details"]["osup_det"] else:
osup_det["txval"] = flt(osup_det["txval"] + d.total, 2) osup_det = self.report_dict["sup_details"]["osup_det"]
osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) osup_det["txval"] = flt(osup_det["txval"] + d.total, 2)
osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2)
return inter_state_supply_details return inter_state_supply_details
def get_inward_nil_exempt(self, state): def get_inward_nil_exempt(self, state):
inward_nil_exempt = frappe.db.sql(""" select a.gst_state, sum(i.base_amount) as base_amount, inward_nil_exempt = frappe.db.sql(""" select p.place_of_supply, sum(i.base_amount) as base_amount,
i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i, `tabAddress` a i.is_nil_exempt, i.is_non_gst from `tabPurchase Invoice` p , `tabPurchase Invoice Item` i
where p.docstatus = 1 and p.name = i.parent and p.supplier_address = a.name where p.docstatus = 1 and p.name = i.parent
and i.is_nil_exempt = 1 or i.is_non_gst = 1 and and i.is_nil_exempt = 1 or i.is_non_gst = 1 and
month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s month(p.posting_date) = %s and year(p.posting_date) = %s and p.company = %s and p.company_gstin = %s
group by a.gst_state """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) group by p.place_of_supply """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)
inward_nil_exempt_details = { inward_nil_exempt_details = {
"gst": { "gst": {
@@ -364,14 +365,15 @@ class GSTR3BReport(Document):
} }
for d in inward_nil_exempt: for d in inward_nil_exempt:
if d.is_nil_exempt == 1 and state == d.gst_state: if d.place_of_supply:
inward_nil_exempt_details["gst"]["intra"] += d.base_amount if d.is_nil_exempt == 1 and state == d.place_of_supply.split("-")[1]:
elif d.is_nil_exempt == 1 and state != d.gst_state: inward_nil_exempt_details["gst"]["intra"] += d.base_amount
inward_nil_exempt_details["gst"]["inter"] += d.base_amount elif d.is_nil_exempt == 1 and state != d.place_of_supply.split("-")[1]:
elif d.is_non_gst == 1 and state == d.gst_state: inward_nil_exempt_details["gst"]["inter"] += d.base_amount
inward_nil_exempt_details["non_gst"]["inter"] += d.base_amount elif d.is_non_gst == 1 and state == d.place_of_supply.split("-")[1]:
elif d.is_non_gst == 1 and state != d.gst_state: inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount
inward_nil_exempt_details["non_gst"]["intra"] += d.base_amount elif d.is_non_gst == 1 and state != d.place_of_supply.split("-")[1]:
inward_nil_exempt_details["non_gst"]["inter"] += d.base_amount
return inward_nil_exempt_details return inward_nil_exempt_details

View File

@@ -176,6 +176,9 @@ def create_purchase_invoices():
do_not_save=1 do_not_save=1
) )
pi1.shipping_address = "_Test Supplier GST-1-Billing"
pi1.save()
pi1.submit() pi1.submit()
def make_suppliers(): def make_suppliers():
@@ -218,6 +221,7 @@ def make_suppliers():
"link_name": "_Test Registered Supplier" "link_name": "_Test Registered Supplier"
}) })
address.is_shipping_address = 1
address.save() address.save()
if not frappe.db.exists('Address', '_Test Supplier GST-2-Billing'): if not frappe.db.exists('Address', '_Test Supplier GST-2-Billing'):

View File

@@ -252,7 +252,7 @@ class Company(NestedSet):
def set_mode_of_payment_account(self): def set_mode_of_payment_account(self):
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name') cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
if cash and self.default_cash_account \ if cash and self.default_cash_account \
and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': 'Cash'}): and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': cash}):
mode_of_payment = frappe.get_doc('Mode of Payment', cash) mode_of_payment = frappe.get_doc('Mode of Payment', cash)
mode_of_payment.append('accounts', { mode_of_payment.append('accounts', {
'company': self.name, 'company': self.name,

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'
@@ -165,7 +165,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'))
@@ -218,4 +218,4 @@ def get_item_group_defaults(item, company):
row.pop("name") row.pop("name")
return row return row
return frappe._dict() return frappe._dict()

View File

@@ -197,7 +197,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() },
__('Create')); __('Create'));
} }
} }

View File

@@ -468,7 +468,6 @@
}, },
{ {
"default": "0", "default": "0",
"depends_on": "has_batch_no",
"fieldname": "retain_sample", "fieldname": "retain_sample",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Retain Sample" "label": "Retain Sample"

View File

@@ -190,7 +190,7 @@ erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend
frappe.set_route("Form", doc.doctype, doc.name); frappe.set_route("Form", doc.doctype, doc.name);
} }
else { else {
frappe.msgprint(__("Retention Stock Entry already created or Sample Quantity not provided")); frappe.msgprint(__("Purchase Receipt doesn't have any Item for which Retain Sample is enabled."));
} }
} }
}); });

View File

@@ -9,9 +9,9 @@
</p> </p>
<!-- description --> <!-- description -->
<div itemprop="description"> <div itemprop="description">
{% if frappe.utils.strip_html(doc.web_long_description) %} {% if frappe.utils.strip_html(doc.web_long_description or '') %}
{{ doc.web_long_description | safe }} {{ doc.web_long_description | safe }}
{% elif frappe.utils.strip_html(doc.description) %} {% elif frappe.utils.strip_html(doc.description or '') %}
{{ doc.description | safe }} {{ doc.description | safe }}
{% else %} {% else %}
{{ _("No description given") }} {{ _("No description given") }}

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