Merge branch 'develop' into quoted-item-report-v2

This commit is contained in:
Marica 2020-08-31 12:45:05 +05:30 committed by GitHub
commit ee56d0e0a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 179 additions and 41 deletions

View File

@ -447,7 +447,7 @@
{ {
"allow_on_submit": 1, "allow_on_submit": 1,
"fieldname": "po_no", "fieldname": "po_no",
"fieldtype": "Small Text", "fieldtype": "Data",
"hide_days": 1, "hide_days": 1,
"hide_seconds": 1, "hide_seconds": 1,
"label": "Customer's Purchase Order", "label": "Customer's Purchase Order",
@ -1946,7 +1946,7 @@
"idx": 181, "idx": 181,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-08-03 23:31:12.675040", "modified": "2020-08-27 01:56:28.532140",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -3,6 +3,22 @@
frappe.ui.form.on('Shipping Rule', { frappe.ui.form.on('Shipping Rule', {
refresh: function(frm) { refresh: function(frm) {
frm.set_query("cost_center", function() {
return {
filters: {
company: frm.doc.company
}
}
})
frm.set_query("account", function() {
return {
filters: {
company: frm.doc.company
}
}
})
frm.trigger('toggle_reqd'); frm.trigger('toggle_reqd');
}, },
calculate_based_on: function(frm) { calculate_based_on: function(frm) {
@ -12,4 +28,4 @@ frappe.ui.form.on('Shipping Rule', {
frm.toggle_reqd("shipping_amount", frm.doc.calculate_based_on === 'Fixed'); frm.toggle_reqd("shipping_amount", frm.doc.calculate_based_on === 'Fixed');
frm.toggle_reqd("conditions", frm.doc.calculate_based_on !== 'Fixed'); frm.toggle_reqd("conditions", frm.doc.calculate_based_on !== 'Fixed');
} }
}); });

View File

@ -173,7 +173,7 @@ class PartyLedgerSummaryReport(object):
from `tabGL Entry` gle from `tabGL Entry` gle
{join} {join}
where where
gle.docstatus < 2 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != '' gle.docstatus < 2 and gle.is_cancelled = 0 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != ''
and gle.posting_date <= %(to_date)s {conditions} and gle.posting_date <= %(to_date)s {conditions}
order by gle.posting_date order by gle.posting_date
""".format(join=join, join_field=join_field, conditions=conditions), self.filters, as_dict=True) """.format(join=join, join_field=join_field, conditions=conditions), self.filters, as_dict=True)
@ -248,7 +248,7 @@ class PartyLedgerSummaryReport(object):
from from
`tabGL Entry` `tabGL Entry`
where where
docstatus < 2 docstatus < 2 and is_cancelled = 0
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.account_type = '{income_or_expense}' where acc.name = gle.account and acc.account_type = '{income_or_expense}'

View File

@ -276,6 +276,9 @@ class BuyingController(StockController):
qty_to_be_received_map = get_qty_to_be_received(purchase_orders) qty_to_be_received_map = get_qty_to_be_received(purchase_orders)
for item in self.get('items'): for item in self.get('items'):
if not item.purchase_order:
continue
# reset raw_material cost # reset raw_material cost
item.rm_supp_cost = 0 item.rm_supp_cost = 0
@ -288,6 +291,12 @@ class BuyingController(StockController):
fg_yet_to_be_received = qty_to_be_received_map.get(item_key) fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
if not fg_yet_to_be_received:
frappe.throw(_("Row #{0}: Item {1} is already fully received in Purchase Order {2}")
.format(item.idx, frappe.bold(item.item_code),
frappe.utils.get_link_to_form("Purchase Order", item.purchase_order)),
title=_("Limit Crossed"))
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code) transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code) backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)

View File

@ -9,6 +9,7 @@ from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from erpnext.controllers.accounts_controller import validate_conversion_rate, \ from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax validate_taxes_and_charges, validate_inclusive_tax
from erpnext.stock.get_item_details import _get_item_tax_template from erpnext.stock.get_item_details import _get_item_tax_template
from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
class calculate_taxes_and_totals(object): class calculate_taxes_and_totals(object):
def __init__(self, doc): def __init__(self, doc):
@ -209,7 +210,7 @@ class calculate_taxes_and_totals(object):
elif tax.charge_type == "On Previous Row Total": elif tax.charge_type == "On Previous Row Total":
current_tax_fraction = (tax_rate / 100.0) * \ current_tax_fraction = (tax_rate / 100.0) * \
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
elif tax.charge_type == "On Item Quantity": elif tax.charge_type == "On Item Quantity":
inclusive_tax_amount_per_qty = flt(tax_rate) inclusive_tax_amount_per_qty = flt(tax_rate)
@ -607,7 +608,7 @@ class calculate_taxes_and_totals(object):
base_rate_with_margin = 0.0 base_rate_with_margin = 0.0
if item.price_list_rate: if item.price_list_rate:
if item.pricing_rules and not self.doc.ignore_pricing_rule: if item.pricing_rules and not self.doc.ignore_pricing_rule:
for d in json.loads(item.pricing_rules): for d in get_applied_pricing_rules(item.pricing_rules):
pricing_rule = frappe.get_cached_doc('Pricing Rule', d) pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\ if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\

View File

@ -226,7 +226,9 @@ let check_and_set_availability = function(frm) {
primary_action_label: __('Book'), primary_action_label: __('Book'),
primary_action: function() { primary_action: function() {
frm.set_value('appointment_time', selected_slot); frm.set_value('appointment_time', selected_slot);
frm.set_value('duration', duration); if (!frm.doc.duration) {
frm.set_value('duration', duration);
}
frm.set_value('practitioner', d.get_value('practitioner')); frm.set_value('practitioner', d.get_value('practitioner'));
frm.set_value('department', d.get_value('department')); frm.set_value('department', d.get_value('department'));
frm.set_value('appointment_date', d.get_value('appointment_date')); frm.set_value('appointment_date', d.get_value('appointment_date'));

View File

@ -90,6 +90,7 @@ def update_latest_price_in_all_boms():
update_cost() update_cost()
def replace_bom(args): def replace_bom(args):
frappe.db.auto_commit_on_many_writes = 1
args = frappe._dict(args) args = frappe._dict(args)
doc = frappe.get_doc("BOM Update Tool") doc = frappe.get_doc("BOM Update Tool")
@ -97,6 +98,8 @@ def replace_bom(args):
doc.new_bom = args.new_bom doc.new_bom = args.new_bom
doc.replace_bom() doc.replace_bom()
frappe.db.auto_commit_on_many_writes = 0
def update_cost(): def update_cost():
frappe.db.auto_commit_on_many_writes = 1 frappe.db.auto_commit_on_many_writes = 1
bom_list = get_boms_in_bottom_up_order() bom_list = get_boms_in_bottom_up_order()

View File

@ -718,6 +718,7 @@ erpnext.patches.v13_0.delete_report_requested_items_to_order
erpnext.patches.v12_0.update_item_tax_template_company erpnext.patches.v12_0.update_item_tax_template_company
erpnext.patches.v13_0.move_branch_code_to_bank_account erpnext.patches.v13_0.move_branch_code_to_bank_account
erpnext.patches.v13_0.healthcare_lab_module_rename_doctypes erpnext.patches.v13_0.healthcare_lab_module_rename_doctypes
erpnext.patches.v13_0.add_standard_navbar_items #4
erpnext.patches.v13_0.stock_entry_enhancements erpnext.patches.v13_0.stock_entry_enhancements
erpnext.patches.v12_0.update_state_code_for_daman_and_diu erpnext.patches.v12_0.update_state_code_for_daman_and_diu
erpnext.patches.v12_0.rename_lost_reason_detail erpnext.patches.v12_0.rename_lost_reason_detail

View File

@ -0,0 +1,7 @@
from __future__ import unicode_literals
# import frappe
from erpnext.setup.install import add_standard_navbar_items
def execute():
# Add standard navbar items for ERPNext in Navbar Settings
add_standard_navbar_items()

View File

@ -3,32 +3,6 @@
frappe.provide('erpnext'); frappe.provide('erpnext');
// add toolbar icon
$(document).bind('toolbar_setup', function() {
frappe.app.name = "ERPNext";
frappe.help_feedback_link = '<p><a class="text-muted" \
href="https://discuss.erpnext.com">Feedback</a></p>'
$('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
$('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
// default documentation goes to erpnext
// $('[data-link-type="documentation"]').attr('data-path', '/erpnext/manual/index');
// additional help links for erpnext
var $help_menu = $('.dropdown-help ul .documentation-links');
$('<li><a data-link-type="forum" href="https://erpnext.com/docs/user/manual" \
target="_blank">'+__('Documentation')+'</a></li>').insertBefore($help_menu);
$('<li><a data-link-type="forum" href="https://discuss.erpnext.com" \
target="_blank">'+__('User Forum')+'</a></li>').insertBefore($help_menu);
$('<li><a href="https://github.com/frappe/erpnext/issues" \
target="_blank">'+__('Report an Issue')+'</a></li>').insertBefore($help_menu);
});
// preferred modules for breadcrumbs // preferred modules for breadcrumbs
$.extend(frappe.breadcrumbs.preferred, { $.extend(frappe.breadcrumbs.preferred, {
"Item Group": "Stock", "Item Group": "Stock",

View File

@ -33,7 +33,7 @@ def get_data():
}, },
{ {
'label': _('Support'), 'label': _('Support'),
'items': ['Issue', 'Maintenance Visit'] 'items': ['Issue', 'Maintenance Visit', 'Installation Note', 'Warranty Claim']
}, },
{ {
'label': _('Projects'), 'label': _('Projects'),

View File

@ -285,9 +285,17 @@ def _make_customer(source_name, ignore_permissions=False):
return customer return customer
else: else:
raise raise
except frappe.MandatoryError: except frappe.MandatoryError as e:
mandatory_fields = e.args[0].split(':')[1].split(',')
mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
frappe.local.message_log = [] frappe.local.message_log = []
frappe.throw(_("Please create Customer from Lead {0}").format(lead_name)) lead_link = frappe.utils.get_link_to_form("Lead", lead_name)
message = _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
message += _("Please create Customer from Lead {0}.").format(lead_link)
frappe.throw(message, title=_("Mandatory Missing"))
else: else:
return customer_name return customer_name
else: else:

View File

@ -356,7 +356,7 @@ erpnext.PointOfSale.ItemCart = class {
onchange: function() { onchange: function() {
if (this.value || this.value == 0) { if (this.value || this.value == 0) {
const frm = me.events.get_frm(); const frm = me.events.get_frm();
frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', this.value); frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', flt(this.value));
me.hide_discount_control(this.value); me.hide_discount_control(this.value);
} }
}, },
@ -948,4 +948,4 @@ erpnext.PointOfSale.ItemCart = class {
show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none'); show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
} }
} }

View File

@ -26,7 +26,8 @@ def delete_company_transactions(company_name):
tabDocField where fieldtype='Link' and options='Company'"""): tabDocField where fieldtype='Link' and options='Company'"""):
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget", if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
"Party Account", "Employee", "Sales Taxes and Charges Template", "Party Account", "Employee", "Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template", "POS Profile", 'BOM'): "Purchase Taxes and Charges Template", "POS Profile", "BOM",
"Company", "Bank Account"):
delete_for_doctype(doctype, company_name) delete_for_doctype(doctype, company_name)
# reset company values # reset company values

View File

@ -26,6 +26,7 @@ def after_install():
create_default_success_action() create_default_success_action()
create_default_energy_point_rules() create_default_energy_point_rules()
add_company_to_session_defaults() add_company_to_session_defaults()
add_standard_navbar_items()
frappe.db.commit() frappe.db.commit()
@ -104,3 +105,45 @@ def add_company_to_session_defaults():
"ref_doctype": "Company" "ref_doctype": "Company"
}) })
settings.save() settings.save()
def add_standard_navbar_items():
navbar_settings = frappe.get_single("Navbar Settings")
erpnext_navbar_items = [
{
'item_label': 'Documentation',
'item_type': 'Route',
'route': 'https://erpnext.com/docs/user/manual',
'is_standard': 1
},
{
'item_label': 'User Forum',
'item_type': 'Route',
'route': 'https://discuss.erpnext.com',
'is_standard': 1
},
{
'item_label': 'Report an Issue',
'item_type': 'Route',
'route': 'https://github.com/frappe/erpnext/issues',
'is_standard': 1
}
]
current_nabvar_items = navbar_settings.help_dropdown
navbar_settings.set('help_dropdown', [])
for item in erpnext_navbar_items:
navbar_settings.append('help_dropdown', item)
for item in current_nabvar_items:
navbar_settings.append('help_dropdown', {
'item_label': item.item_label,
'item_type': item.item_type,
'route': item.route,
'action': item.action,
'is_standard': item.is_standard,
'hidden': item.hidden
})
navbar_settings.save()

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import unittest
import json
import frappe, erpnext import frappe, erpnext
import frappe.defaults import frappe.defaults
from frappe.utils import cint, flt, cstr, today, random_string from frappe.utils import cint, flt, cstr, today, random_string
@ -152,13 +153,78 @@ class TestPurchaseReceipt(unittest.TestCase):
qty=100, basic_rate=100, company="_Test Company with perpetual inventory") qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=0, is_subcontracted="Yes", pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=0, is_subcontracted="Yes",
company="_Test Company with perpetual inventory", warehouse='Stores - TCP1', supplier_warehouse='Work In Progress - TCP1') company="_Test Company with perpetual inventory", warehouse='Stores - TCP1', supplier_warehouse='Work In Progress - TCP1')
gl_entries = get_gl_entries("Purchase Receipt", pr.name) gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertFalse(gl_entries) self.assertFalse(gl_entries)
set_perpetual_inventory(0) set_perpetual_inventory(0)
def test_subcontracting_over_receipt(self):
"""
Behaviour: Raise multiple PRs against one PO that in total
receive more than the required qty in the PO.
Expected Result: Error Raised for Over Receipt against PO.
"""
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
make_subcontracted_item, create_purchase_order)
from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt,
make_rm_stock_entry as make_subcontract_transfer_entry)
update_backflush_based_on("Material Transferred for Subcontract")
item_code = "_Test Subcontracted FG Item 1"
make_subcontracted_item(item_code)
po = create_purchase_order(item_code=item_code, qty=1,
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
#stock raw materials in a warehouse before transfer
make_stock_entry(target="_Test Warehouse - _TC",
item_code="_Test Item Home Desktop 100", qty=1, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 1", qty=1, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code = "_Test Item", qty=1, basic_rate=100)
rm_items = [
{
"item_code": item_code,
"rm_item_code": po.supplied_items[0].rm_item_code,
"item_name": "_Test Item",
"qty": po.supplied_items[0].required_qty,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
},
{
"item_code": item_code,
"rm_item_code": po.supplied_items[1].rm_item_code,
"item_name": "Test Extra Item 1",
"qty": po.supplied_items[1].required_qty,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
},
{
"item_code": item_code,
"rm_item_code": po.supplied_items[2].rm_item_code,
"item_name": "_Test Item Home Desktop 100",
"qty": po.supplied_items[2].required_qty,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "Nos"
}
]
rm_item_string = json.dumps(rm_items)
se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
se.to_warehouse = "_Test Warehouse 1 - _TC"
se.save()
se.submit()
pr1 = make_purchase_receipt(po.name)
pr2 = make_purchase_receipt(po.name)
pr1.submit()
self.assertRaises(frappe.ValidationError, pr2.submit)
def test_serial_no_supplier(self): def test_serial_no_supplier(self):
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1) pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
self.assertEqual(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"), self.assertEqual(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"),

View File

@ -20,6 +20,13 @@ frappe.ready(() => {
options: 'Email', options: 'Email',
reqd: 1 reqd: 1
}, },
{
fieldtype: 'Data',
label: __('Phone Number'),
fieldname: 'phone',
options: 'Phone',
reqd: 1
},
{ {
fieldtype: 'Data', fieldtype: 'Data',
label: __('Subject'), label: __('Subject'),