Merge branch 'version-11-hotfix' into v11-work-order-bugs

This commit is contained in:
Rohan
2019-09-25 14:45:21 +05:30
committed by GitHub
27 changed files with 1524 additions and 1435 deletions

View File

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

View File

@@ -58,7 +58,6 @@ class ReceivablePayableReport(object):
self.invoices = set()
def get_data(self):
t1 = now()
self.get_gl_entries()
self.voucher_balance = OrderedDict()
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
@@ -72,6 +71,9 @@ class ReceivablePayableReport(object):
# fetch future payments against invoices
self.get_future_payments()
# Get return entries
self.get_return_entries()
self.data = []
for gle in self.gl_entries:
self.update_voucher_balance(gle)
@@ -90,6 +92,7 @@ class ReceivablePayableReport(object):
party = gle.party,
posting_date = gle.posting_date,
remarks = gle.remarks,
account_currency = gle.account_currency,
invoiced = 0.0,
paid = 0.0,
credit_note = 0.0,
@@ -105,7 +108,6 @@ class ReceivablePayableReport(object):
# get the row where this balance needs to be updated
# if its a payment, it will return the linked invoice or will be considered as advance
row = self.get_voucher_balance(gle)
# gle_balance will be the total "debit - credit" for receivable type reports and
# and vice-versa for payable type reports
gle_balance = self.get_gle_balance(gle)
@@ -130,7 +132,18 @@ class ReceivablePayableReport(object):
if gle.against_voucher:
# find invoice
voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party))
against_voucher = gle.against_voucher
# If payment is made against credit note
# and credit note is made against a Sales Invoice
# then consider the payment against original sales invoice.
if gle.against_voucher_type in ('Sales Invoice', 'Purchase Invoice'):
if gle.against_voucher in self.return_entries:
return_against = self.return_entries.get(gle.against_voucher)
if return_against:
against_voucher = return_against
voucher_balance = self.voucher_balance.get((gle.against_voucher_type, against_voucher, gle.party))
if not voucher_balance:
# no invoice, this is an invoice / stand-alone payment / credit note
@@ -257,7 +270,6 @@ class ReceivablePayableReport(object):
# customer / supplier name
party_details = self.get_party_details(row.party)
row.update(party_details)
if self.filters.get(scrub(self.filters.party_type)):
row.currency = row.account_currency
else:
@@ -422,6 +434,19 @@ class ReceivablePayableReport(object):
if row.future_ref:
row.future_ref = ', '.join(row.future_ref)
def get_return_entries(self):
doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
filters={
'is_return': 1,
'docstatus': 1
}
party_field = scrub(self.filters.party_type)
if self.filters.get(party_field):
filters.update({party_field: self.filters.get(party_field)})
self.return_entries = frappe._dict(
frappe.get_all(doctype, filters, ['name', 'return_against'], as_list=1)
)
def set_ageing(self, row):
if self.filters.ageing_based_on == "Due Date":
entry_date = row.due_date
@@ -445,6 +470,10 @@ class ReceivablePayableReport(object):
row.age = (getdate(self.age_as_on) - getdate(entry_date)).days or 0
index = None
if not (self.filters.range1 and self.filters.range2 and self.filters.range3 and self.filters.range4):
self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4 = 30, 60, 90, 120
for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]):
if row.age <= days:
index = i
@@ -673,11 +702,11 @@ class ReceivablePayableReport(object):
def get_chart_data(self):
rows = []
for row in self.data:
rows.append(
{
'values': [row.range1, row.range2, row.range3, row.range4, row.range5]
}
)
values = [row.range1, row.range2, row.range3, row.range4, row.range5]
precision = cint(frappe.db.get_default("float_precision")) or 2
rows.append({
'values': [flt(val, precision) for val in values]
})
self.chart = {
"data": {

View File

@@ -40,7 +40,8 @@ class AccountsReceivableSummary(ReceivablePayableReport):
row.party = party
if self.party_naming_by == "Naming Series":
row.party_name = frappe.get_cached_value(self.party_type, party, [self.party_type + "_name"])
row.party_name = frappe.get_cached_value(self.party_type,
party, frappe.scrub(self.party_type) + "_name")
row.update(party_dict)

View File

@@ -17,7 +17,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
filters.update({"from_date": filters.get("date_range") and filters.get("date_range")[0], "to_date": filters.get("date_range") and filters.get("date_range")[1]})
columns = get_columns(additional_table_columns)
company_currency = erpnext.get_company_currency(filters.get('company'))
company_currency = frappe.get_cached_value('Company', filters.get("company"), "default_currency")
item_list = get_items(filters, additional_query_columns)
if item_list:

View File

@@ -4,11 +4,13 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from erpnext.accounts.report.accounts_receivable.accounts_receivable import get_ageing_data
from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport
from frappe.utils import getdate, flt
def execute(filters=None):
if not filters: filters = {}
if not filters:
filters = {}
validate_filters(filters)
columns = get_columns(filters)
@@ -19,18 +21,29 @@ def execute(filters=None):
for d in entries:
invoice = invoice_details.get(d.against_voucher) or frappe._dict()
if d.reference_type=="Purchase Invoice":
if d.reference_type == "Purchase Invoice":
payment_amount = flt(d.debit) or -1 * flt(d.credit)
else:
payment_amount = flt(d.credit) or -1 * flt(d.debit)
row = [d.voucher_type, d.voucher_no, d.party_type, d.party, d.posting_date, d.against_voucher,
invoice.posting_date, invoice.due_date, d.debit, d.credit, d.remarks]
d.update({
"range1": 0,
"range2": 0,
"range3": 0,
"range4": 0,
"outstanding": payment_amount
})
if d.against_voucher:
row += get_ageing_data(30, 60, 90, 120, d.posting_date, invoice.posting_date, payment_amount)
else:
row += ["", "", "", "", ""]
ReceivablePayableReport(filters).get_ageing_data(invoice.posting_date, d)
row = [
d.voucher_type, d.voucher_no, d.party_type, d.party, d.posting_date, d.against_voucher,
invoice.posting_date, invoice.due_date, d.debit, d.credit, d.remarks,
d.age, d.range1, d.range2, d.range3, d.range4
]
if invoice.due_date:
row.append((getdate(d.posting_date) - getdate(invoice.due_date)).days or 0)

View File

@@ -67,8 +67,8 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
total_tax = 0
for tax_acc in tax_accounts:
if tax_acc not in income_accounts:
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc))
total_tax += tax_amount
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
row.append(tax_amount)
# total tax, grand total, outstanding amount & rounded total

View File

@@ -5,9 +5,8 @@
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Capital Traders",
"modified": "2018-12-12 05:10:02.987274",
"is_standard": "Yes",
"modified": "2019-02-12 05:10:02.987274",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Supplier Ledger Summary",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-08-21 11:25:00.551823",
"modified": "2018-09-21 11:25:00.551823",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Computation Summary",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-08-21 11:33:40.804532",
"modified": "2019-09-24 13:46:16.473711",
"modified_by": "Administrator",
"module": "Accounts",
"name": "TDS Payable Monthly",

View File

@@ -10,7 +10,8 @@ frappe.ui.form.on("Purchase Order", {
frm.custom_make_buttons = {
'Purchase Receipt': 'Receipt',
'Purchase Invoice': 'Invoice',
'Stock Entry': 'Material to Supplier'
'Stock Entry': 'Material to Supplier',
'Payment Entry': 'Payment'
}
frm.set_query("reserve_warehouse", "supplied_items", function() {

View File

@@ -292,6 +292,7 @@ def copy_attributes_to_variant(item, variant):
if not variant.description:
variant.description = ""
else:
if item.variant_based_on=='Item Attribute':
if variant.attributes:
attributes_description = item.description + " "
@@ -299,7 +300,7 @@ def copy_attributes_to_variant(item, variant):
attributes_description += "<div>" + d.attribute + ": " + cstr(d.attribute_value) + "</div>"
if attributes_description not in variant.description:
variant.description += attributes_description
variant.description = attributes_description
def make_variant_item_code(template_item_code, template_item_name, variant):
"""Uses template's item code and abbreviations to make variant's item code"""

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2017-04-17 00:20:27.248275",
"modified": "2019-04-17 00:20:27.248275",
"modified_by": "Administrator",
"module": "CRM",
"name": "Campaign Efficiency",

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2018-09-17 14:40:52.035394",
"modified": "2019-09-19 14:40:52.035394",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Conversion Time",

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Shishuvan Secondary School",
"modified": "2018-02-08 15:11:35.339434",
"modified": "2019-02-08 15:11:35.339434",
"modified_by": "Administrator",
"module": "Education",
"name": "Final Assessment Grades",

File diff suppressed because it is too large Load Diff

View File

@@ -648,7 +648,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
item_dict[key] = item
for item, item_details in item_dict.items():
for d in [["Account", "expense_account", "default_expense_account"],
for d in [["Account", "expense_account", "stock_adjustment_account"],
["Cost Center", "cost_center", "cost_center"], ["Warehouse", "default_warehouse", ""]]:
company_in_record = frappe.db.get_value(d[0], item_details.get(d[1]), "company")
if not item_details.get(d[1]) or (company_in_record and company != company_in_record):

View File

@@ -105,7 +105,6 @@ class JobCard(Document):
for_quantity, time_in_mins = 0, 0
from_time_list, to_time_list = [], []
for d in frappe.get_all('Job Card',
filters = {'docstatus': 1, 'operation_id': self.operation_id}):
doc = frappe.get_doc('Job Card', d.name)
@@ -125,8 +124,8 @@ class JobCard(Document):
if data.name == self.operation_id:
data.completed_qty = for_quantity
data.actual_operation_time = time_in_mins
data.actual_start_time = min(from_time_list)
data.actual_end_time = max(to_time_list)
data.actual_start_time = min(from_time_list) if from_time_list else None
data.actual_end_time = max(to_time_list) if to_time_list else None
wo.flags.ignore_validate_update_after_submit = True
wo.update_operation_status()

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Gadgets International",
"modified": "2018-05-28 16:22:24.040106",
"modified": "2018-06-28 16:22:24.040106",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Variance Report",

View File

@@ -2,6 +2,7 @@ frappe.provide('frappe.ui.form');
frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
init: function(doctype, after_insert) {
this.skip_redirect_on_error = true;
this._super(doctype, after_insert);
},
@@ -37,8 +38,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("Address Line 1"),
fieldname: "address_line1",
fieldtype: "Data",
reqd: 1
fieldtype: "Data"
},
{
label: __("Address Line 2"),
@@ -56,8 +56,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("City"),
fieldname: "city",
fieldtype: "Data",
reqd: 1,
fieldtype: "Data"
},
{
label: __("State"),
@@ -68,8 +67,7 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
options: "Country",
reqd: 1
options: "Country"
},
{
label: __("Customer POS Id"),

View File

@@ -153,8 +153,7 @@ def get_invoice_summary(items, taxes):
tax_rate=tax.rate,
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount,
taxable_amount=(reference_row.tax_amount if tax.charge_type == 'On Previous Row Amount'
else reference_row.total),
taxable_amount=reference_row.tax_amount,
item_tax_rate={tax.account_head: tax.rate},
charges=True,
type="Actual",
@@ -189,6 +188,10 @@ def get_invoice_summary(items, taxes):
summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason
summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law
if summary_data.get("0.0") and tax.charge_type in ["On Previous Row Total",
"On Previous Row Amount"]:
summary_data[key]["taxable_amount"] = tax.total
if summary_data == {}: #Implies that Zero VAT has not been set on any item.
summary_data.setdefault("0.0", {"tax_amount": 0.0, "taxable_amount": tax.total,
"tax_exemption_reason": tax.tax_exemption_reason, "tax_exemption_law": tax.tax_exemption_law})

View File

@@ -6,8 +6,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Standard",
"modified": "2018-04-26 12:59:38.603649",
"modified": "2019-04-26 12:59:38.603649",
"modified_by": "Administrator",
"module": "Regional",
"name": "HSN-wise-summary of outward supplies",

View File

@@ -340,6 +340,16 @@ def make_contact(args, is_primary_contact=1):
return contact
def make_address(args, is_primary_address=1):
reqd_fields = []
for field in ['city', 'country']:
if not args.get(field):
reqd_fields.append( '<li>' + field.title() + '</li>')
if reqd_fields:
msg = _("Following fields are mandatory to create address:")
frappe.throw("{0} <br><br> <ul>{1}</ul>".format(msg, '\n'.join(reqd_fields)),
title = _("Missing Values Required"))
address = frappe.get_doc({
'doctype': 'Address',
'address_title': args.get('name'),

View File

@@ -10,7 +10,8 @@ frappe.ui.form.on("Sales Order", {
'Sales Invoice': 'Invoice',
'Material Request': 'Material Request',
'Purchase Order': 'Purchase Order',
'Project': 'Project'
'Project': 'Project',
'Payment Entry': "Payment"
}
frm.add_fetch('customer', 'tax_id', 'tax_id');

View File

@@ -7,8 +7,7 @@
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "Delta9",
"modified": "2019-06-12 03:25:36.263179",
"modified": "2019-06-14 03:25:36.263179",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer-wise Item Price",

View File

@@ -209,7 +209,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
args: {
item_code: item.item_code,
warehouse: item.warehouse,
has_batch_no: has_batch_no,
has_batch_no: has_batch_no || 0,
stock_qty: item.stock_qty,
serial_no: item.serial_no || "",
},

View File

@@ -724,7 +724,7 @@ def get_serial_no_details(item_code, warehouse, stock_qty, serial_no):
return {'serial_no': serial_no}
@frappe.whitelist()
def get_bin_details_and_serial_nos(item_code, warehouse, has_batch_no, stock_qty=None, serial_no=None):
def get_bin_details_and_serial_nos(item_code, warehouse, has_batch_no=None, stock_qty=None, serial_no=None):
bin_details_and_serial_nos = {}
bin_details_and_serial_nos.update(get_bin_details(item_code, warehouse))
if flt(stock_qty) > 0:

View File

@@ -15,8 +15,8 @@ def execute(filters=None):
def get_columns():
columns = [
_("Company") + ":Link/Item:250",
_("Warehouse") + ":Link/Item:150",
_("Company") + ":Link/Company:250",
_("Warehouse") + ":Link/Warehouse:150",
_("Item") + ":Link/Item:150",
_("Description") + "::300",
_("Current Qty") + ":Float:100",
@@ -31,7 +31,7 @@ def get_total_stock(filters):
if filters.get("group_by") == "Warehouse":
if filters.get("company"):
conditions += " AND warehouse.company = '%s'" % frappe.db.escape(filters.get("company"), percent=False)
conditions += " GROUP BY ledger.warehouse, item.item_code"
columns += "'' as company, ledger.warehouse"
else: