Merge branch 'develop' into exploded-item-rate

This commit is contained in:
Marica 2020-07-06 23:35:37 +05:30 committed by GitHub
commit d187a6ac48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 127 additions and 110 deletions

View File

@ -133,7 +133,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
acc = frappe.get_doc("Account", account) acc = frappe.get_doc("Account", account)
try: try:
year_start_date = get_fiscal_year(date, verbose=0)[1] year_start_date = get_fiscal_year(date, company=company, verbose=0)[1]
except FiscalYearError: except FiscalYearError:
if getdate(date) > getdate(nowdate()): if getdate(date) > getdate(nowdate()):
# if fiscal year not found and the date is greater than today # if fiscal year not found and the date is greater than today
@ -787,10 +787,10 @@ def get_children(doctype, parent, company, is_root=False):
company_currency = frappe.get_cached_value('Company', company, "default_currency") company_currency = frappe.get_cached_value('Company', company, "default_currency")
for each in acc: for each in acc:
each["company_currency"] = company_currency each["company_currency"] = company_currency
each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company))
if each.account_currency != company_currency: if each.account_currency != company_currency:
each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company))
return acc return acc

View File

@ -35,11 +35,9 @@ class Asset(AccountsController):
if not self.booked_fixed_asset and self.validate_make_gl_entry(): if not self.booked_fixed_asset and self.validate_make_gl_entry():
self.make_gl_entries() self.make_gl_entries()
def before_cancel(self):
self.cancel_auto_gen_movement()
def on_cancel(self): def on_cancel(self):
self.validate_cancellation() self.validate_cancellation()
self.cancel_movement_entries()
self.delete_depreciation_entries() self.delete_depreciation_entries()
self.set_status() self.set_status()
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry') self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
@ -134,19 +132,6 @@ class Asset(AccountsController):
Please do not book expense of multiple assets against one single Asset.") Please do not book expense of multiple assets against one single Asset.")
.format(frappe.bold("equal"), "<br>"), title=_("Invalid Gross Purchase Amount")) .format(frappe.bold("equal"), "<br>"), title=_("Invalid Gross Purchase Amount"))
def cancel_auto_gen_movement(self):
movements = frappe.db.sql(
"""SELECT asm.name, asm.docstatus
FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item
WHERE asm_item.parent=asm.name and asm_item.asset=%s and asm.docstatus=1""", self.name, as_dict=1)
if len(movements) > 1:
frappe.throw(_('Asset has multiple Asset Movement Entries which has to be \
cancelled manually to cancel this asset.'))
if movements:
movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
movement.flags.ignore_validate = True
movement.cancel()
def make_asset_movement(self): def make_asset_movement(self):
reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
reference_docname = self.purchase_receipt or self.purchase_invoice reference_docname = self.purchase_receipt or self.purchase_invoice
@ -413,6 +398,16 @@ class Asset(AccountsController):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"): if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status)) frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status))
def cancel_movement_entries(self):
movements = frappe.db.sql(
"""SELECT asm.name, asm.docstatus
FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item
WHERE asm_item.parent=asm.name and asm_item.asset=%s and asm.docstatus=1""", self.name, as_dict=1)
for movement in movements:
movement = frappe.get_doc('Asset Movement', movement.get('name'))
movement.cancel()
def delete_depreciation_entries(self): def delete_depreciation_entries(self):
for d in self.get("schedules"): for d in self.get("schedules"):
if d.journal_entry: if d.journal_entry:

View File

@ -88,33 +88,9 @@ class AssetMovement(Document):
def on_submit(self): def on_submit(self):
self.set_latest_location_in_asset() self.set_latest_location_in_asset()
def before_cancel(self):
self.validate_last_movement()
def on_cancel(self): def on_cancel(self):
self.set_latest_location_in_asset() self.set_latest_location_in_asset()
def validate_last_movement(self):
for d in self.assets:
auto_gen_movement_entry = frappe.db.sql(
"""
SELECT asm.name
FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm
WHERE
asm.docstatus=1 and
asm_item.parent=asm.name and
asm_item.asset=%s and
asm.company=%s and
asm_item.source_location is NULL and
asm.purpose=%s
ORDER BY
asm.transaction_date asc
""", (d.asset, self.company, 'Receipt'), as_dict=1)
if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name:
frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \
auto generated for Asset {1}').format(self.name, d.asset))
def set_latest_location_in_asset(self): def set_latest_location_in_asset(self):
current_location, current_employee = '', '' current_location, current_employee = '', ''
cond = "1=1" cond = "1=1"

View File

@ -79,10 +79,12 @@ class TestLoan(unittest.TestCase):
"qty": 4000.00, "qty": 4000.00,
}] }]
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledge, "Repay Over Number of Periods", 12) loan_application = create_loan_application('_Test Company', self.applicant2,
'Stock Loan', pledge, "Repay Over Number of Periods", 12)
create_pledge(loan_application) create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application) loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
12, loan_application)
self.assertEquals(loan.loan_amount, 1000000) self.assertEquals(loan.loan_amount, 1000000)
def test_loan_disbursement(self): def test_loan_disbursement(self):
@ -92,6 +94,7 @@ class TestLoan(unittest.TestCase):
}] }]
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledge, "Repay Over Number of Periods", 12) loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledge, "Repay Over Number of Periods", 12)
create_pledge(loan_application) create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application) loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
@ -217,7 +220,8 @@ class TestLoan(unittest.TestCase):
"qty": 2000.00 "qty": 2000.00
}] }]
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledges) loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledges,
"Repay Over Number of Periods", 12)
create_pledge(loan_application) create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application, loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application,
@ -247,7 +251,9 @@ class TestLoan(unittest.TestCase):
"haircut": 50, "haircut": 50,
}] }]
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledges) loan_application = create_loan_application('_Test Company', self.applicant2,
'Stock Loan', pledges, "Repay Over Number of Periods", 12)
create_pledge(loan_application) create_pledge(loan_application)
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application) loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)

View File

@ -105,7 +105,7 @@ class TestSalarySlip(unittest.TestCase):
#Gross pay calculation based on attendances #Gross pay calculation based on attendances
gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay)) gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
self.assertEqual(ss.gross_pay, gross_pay) self.assertEqual(flt(ss.gross_pay, 2), flt(gross_pay, 2))
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")

View File

@ -183,7 +183,8 @@
{ {
"fieldname": "progress", "fieldname": "progress",
"fieldtype": "Percent", "fieldtype": "Percent",
"label": "% Progress" "label": "% Progress",
"no_copy": 1
}, },
{ {
"default": "0", "default": "0",
@ -356,6 +357,7 @@
"fieldname": "completed_by", "fieldname": "completed_by",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Completed By", "label": "Completed By",
"no_copy": 1,
"options": "User" "options": "User"
} }
], ],
@ -364,7 +366,7 @@
"is_tree": 1, "is_tree": 1,
"links": [], "links": [],
"max_attachments": 5, "max_attachments": 5,
"modified": "2020-03-18 18:08:44.153211", "modified": "2020-07-03 12:36:04.960457",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Task", "name": "Task",

View File

@ -85,6 +85,10 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
args.posting_date, args.party_type=="Customer" ? "customer": "supplier")) return; args.posting_date, args.party_type=="Customer" ? "customer": "supplier")) return;
} }
if (!erpnext.utils.validate_mandatory(frm, "Company", frm.doc.company, args.party_type=="Customer" ? "customer": "supplier")) {
return;
}
args.currency = frm.doc.currency; args.currency = frm.doc.currency;
args.company = frm.doc.company; args.company = frm.doc.company;
args.doctype = frm.doc.doctype; args.doctype = frm.doc.doctype;
@ -188,6 +192,10 @@ erpnext.utils.set_taxes_from_address = function(frm, triggered_from_field, billi
erpnext.utils.set_taxes = function(frm, triggered_from_field) { erpnext.utils.set_taxes = function(frm, triggered_from_field) {
if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
if (!erpnext.utils.validate_mandatory(frm, "Company", frm.doc.company, triggered_from_field)) {
return;
}
if (!erpnext.utils.validate_mandatory(frm, "Lead / Customer / Supplier", if (!erpnext.utils.validate_mandatory(frm, "Lead / Customer / Supplier",
frm.doc.customer || frm.doc.supplier || frm.doc.lead || frm.doc.party_name, triggered_from_field)) { frm.doc.customer || frm.doc.supplier || frm.doc.lead || frm.doc.party_name, triggered_from_field)) {
return; return;
@ -256,7 +264,7 @@ erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
if (!value) { if (!value) {
frm.doc[trigger_on] = ""; frm.doc[trigger_on] = "";
refresh_field(trigger_on); refresh_field(trigger_on);
frappe.msgprint(__("Please enter {0} first", [label])); frappe.throw({message:__("Please enter {0} first", [label]), title:__("Mandatory")});
return false; return false;
} }
return true; return true;

View File

@ -5,7 +5,9 @@ frappe.ui.form.on('Quality Feedback', {
refresh: function(frm) { refresh: function(frm) {
frm.set_value("date", frappe.datetime.get_today()); frm.set_value("date", frappe.datetime.get_today());
}, },
template: function(frm) { template: function(frm) {
if (frm.doc.template) {
frappe.call({ frappe.call({
"method": "frappe.client.get", "method": "frappe.client.get",
args: { args: {
@ -13,13 +15,18 @@ frappe.ui.form.on('Quality Feedback', {
name: frm.doc.template name: frm.doc.template
}, },
callback: function(data) { callback: function(data) {
if (data && data.message) {
frm.fields_dict.parameters.grid.remove_all(); frm.fields_dict.parameters.grid.remove_all();
for (var i in data.message.parameters){
frm.add_child("parameters"); // fetch parameters from template and autofill
frm.fields_dict.parameters.get_value()[i].parameter = data.message.parameters[i].parameter; for (let template_parameter of data.message.parameters) {
let row = frm.add_child("parameters");
row.parameter = template_parameter.parameter;
} }
frm.refresh(); frm.refresh();
} }
}); }
});
}
} }
}); });

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "format:FDBK-{#####}", "autoname": "format:FDBK-{#####}",
"creation": "2019-05-26 21:23:05.308379", "creation": "2019-05-26 21:23:05.308379",
"doctype": "DocType", "doctype": "DocType",
@ -53,12 +54,13 @@
{ {
"fieldname": "document_name", "fieldname": "document_name",
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"label": "Name", "label": "Feedback By",
"options": "document_type", "options": "document_type",
"reqd": 1 "reqd": 1
} }
], ],
"modified": "2019-05-28 15:16:01.161662", "links": [],
"modified": "2020-07-03 15:50:58.589302",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Quality Management", "module": "Quality Management",
"name": "Quality Feedback", "name": "Quality Feedback",

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"autoname": "format:TMPL-{template}", "autoname": "format:TMPL-{template}",
"creation": "2019-05-26 21:17:24.283061", "creation": "2019-05-26 21:17:24.283061",
"doctype": "DocType", "doctype": "DocType",
@ -30,10 +31,12 @@
"fieldname": "parameters", "fieldname": "parameters",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Parameters", "label": "Parameters",
"options": "Quality Feedback Template Parameter" "options": "Quality Feedback Template Parameter",
"reqd": 1
} }
], ],
"modified": "2019-05-26 21:48:47.770610", "links": [],
"modified": "2020-07-03 16:06:03.749415",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Quality Management", "module": "Quality Management",
"name": "Quality Feedback Template", "name": "Quality Feedback Template",

View File

@ -11,6 +11,9 @@ def update_itemised_tax_data(doc):
for row in doc.items: for row in doc.items:
tax_rate = 0.0 tax_rate = 0.0
item_tax_rate = 0.0
if row.item_tax_rate:
item_tax_rate = frappe.parse_json(row.item_tax_rate) item_tax_rate = frappe.parse_json(row.item_tax_rate)
# First check if tax rate is present # First check if tax rate is present
@ -18,7 +21,7 @@ def update_itemised_tax_data(doc):
if item_tax_rate: if item_tax_rate:
for account, rate in iteritems(item_tax_rate): for account, rate in iteritems(item_tax_rate):
tax_rate += rate tax_rate += rate
elif itemised_tax.get(row.item_code): elif row.item_code and itemised_tax.get(row.item_code):
tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()]) tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()])
row.tax_rate = flt(tax_rate, row.precision("tax_rate")) row.tax_rate = flt(tax_rate, row.precision("tax_rate"))

View File

@ -637,6 +637,10 @@ def get_item_price(args, item_code, ignore_party=False):
conditions += """ and %(transaction_date)s between conditions += """ and %(transaction_date)s between
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')"""
if args.get('posting_date'):
conditions += """ and %(posting_date)s between
ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')"""
return frappe.db.sql(""" select name, price_list_rate, uom return frappe.db.sql(""" select name, price_list_rate, uom
from `tabItem Price` {conditions} from `tabItem Price` {conditions}
order by valid_from desc, uom desc """.format(conditions=conditions), args) order by valid_from desc, uom desc """.format(conditions=conditions), args)
@ -657,6 +661,7 @@ def get_price_list_rate_for(args, item_code):
"supplier": args.get('supplier'), "supplier": args.get('supplier'),
"uom": args.get('uom'), "uom": args.get('uom'),
"transaction_date": args.get('transaction_date'), "transaction_date": args.get('transaction_date'),
"posting_date": args.get('posting_date'),
} }
item_price_data = 0 item_price_data = 0

View File

@ -120,6 +120,16 @@ class TransactionBase(StatusUpdater):
def validate_rate_with_reference_doc(self, ref_details): def validate_rate_with_reference_doc(self, ref_details):
buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
selling_doctypes = ["Sales Invoice", "Delivery Note"]
if self.doctype in buying_doctypes:
to_disable = "Maintain same rate throughout Purchase cycle"
settings_page = "Buying Settings"
else:
to_disable = "Maintain same rate throughout Sales cycle"
settings_page = "Selling Settings"
for ref_dt, ref_dn_field, ref_link_field in ref_details: for ref_dt, ref_dn_field, ref_link_field in ref_details:
for d in self.get("items"): for d in self.get("items"):
if d.get(ref_link_field): if d.get(ref_link_field):
@ -129,8 +139,8 @@ class TransactionBase(StatusUpdater):
frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ") frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate)) .format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.") frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
.format(frappe.bold(_("Maintain Same Rate Throughout Sales Cycle")), .format(frappe.bold(_(to_disable)),
get_link_to_form("Selling Settings", "Selling Settings", frappe.bold("Selling Settings")))) get_link_to_form(settings_page, settings_page, frappe.bold(settings_page))))
def get_link_filters(self, for_doctype): def get_link_filters(self, for_doctype):
if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype): if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):