From ea0ff23891facf6d9150ef2aea14785ab94e9817 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 7 Jul 2016 14:02:26 +0530 Subject: [PATCH] [cleanup] form dashboards --- .../request_for_quotation_dashboard.py | 3 - erpnext/controllers/accounts_controller.py | 71 ++++++++++--------- erpnext/controllers/buying_controller.py | 8 +-- erpnext/controllers/status_updater.py | 31 ++++---- erpnext/demo/data/item.json | 3 +- erpnext/demo/demo.py | 4 +- erpnext/demo/setup_data.py | 5 ++ erpnext/demo/user/purchase.py | 54 ++++++++------ .../material_request_dashboard.py | 3 - 9 files changed, 98 insertions(+), 84 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py index 7a69bf960e3..395e357894b 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py @@ -3,9 +3,6 @@ from frappe import _ data = { 'docstatus': 1, 'fieldname': 'request_for_quotation', - # 'non_standard_fieldnames': { - # 'Purchase Order': 'prevdoc_detail_docname', - # }, 'transactions': [ { 'label': _('Related Documents'), diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 2b67ceb243f..432d09a987a 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -173,6 +173,7 @@ class AccountsController(TransactionBase): ret = get_item_details(args) + for fieldname, value in ret.items(): if item.meta.get_field(fieldname) and value is not None: if (item.get(fieldname) is None or fieldname in force_item_fields): @@ -279,7 +280,7 @@ class AccountsController(TransactionBase): def set_advances(self): """Returns list of advances against Account, Party, Reference""" - + res = self.get_advance_entries() self.set("advances", []) @@ -293,7 +294,7 @@ class AccountsController(TransactionBase): "advance_amount": flt(d.amount), "allocated_amount": flt(d.amount) if d.against_order else 0 }) - + def get_advance_entries(self, include_unallocated=True): if self.doctype == "Sales Invoice": party_account = self.debit_to @@ -309,36 +310,36 @@ class AccountsController(TransactionBase): amount_field = "debit_in_account_currency" order_field = "purchase_order" order_doctype = "Purchase Order" - - order_list = list(set([d.get(order_field) + + order_list = list(set([d.get(order_field) for d in self.get("items") if d.get(order_field)])) - - journal_entries = get_advance_journal_entries(party_type, party, party_account, + + journal_entries = get_advance_journal_entries(party_type, party, party_account, amount_field, order_doctype, order_list, include_unallocated) - - payment_entries = get_advance_payment_entries(party_type, party, party_account, + + payment_entries = get_advance_payment_entries(party_type, party, party_account, order_doctype, order_list, include_unallocated) - + res = journal_entries + payment_entries - + return res def validate_advance_entries(self): order_field = "sales_order" if self.doctype == "Sales Invoice" else "purchase_order" - order_list = list(set([d.get(order_field) + order_list = list(set([d.get(order_field) for d in self.get("items") if d.get(order_field)])) - + if not order_list: return - + advance_entries = self.get_advance_entries(include_unallocated=False) - + if advance_entries: advance_entries_against_si = [d.reference_name for d in self.get("advances")] for d in advance_entries: if not advance_entries_against_si or d.reference_name not in advance_entries_against_si: frappe.msgprint(_("Payment Entry {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.") .format(d.reference_name, d.against_order)) - + def update_against_document_in_jv(self): """ Links invoice and advance voucher: @@ -346,7 +347,7 @@ class AccountsController(TransactionBase): 2. split into multiple rows if partially adjusted, assign against voucher 3. submit advance voucher """ - + if self.doctype == "Sales Invoice": party_type = "Customer" party = self.customer @@ -374,14 +375,14 @@ class AccountsController(TransactionBase): 'dr_or_cr' : dr_or_cr, 'unadjusted_amount' : flt(d.advance_amount), 'allocated_amount' : flt(d.allocated_amount), - 'exchange_rate': (self.conversion_rate + 'exchange_rate': (self.conversion_rate if self.party_account_currency != self.company_currency else 1), - 'grand_total': (self.base_grand_total + 'grand_total': (self.base_grand_total if self.party_account_currency==self.company_currency else self.grand_total), 'outstanding_amount': self.outstanding_amount }) lst.append(args) - + if lst: from erpnext.accounts.utils import reconcile_against_document reconcile_against_document(lst) @@ -467,7 +468,7 @@ class AccountsController(TransactionBase): if self.currency == self.company_currency and advance_paid > order_total: frappe.throw(_("Total advance ({0}) against Order {1} cannot be greater than the Grand Total ({2})") .format(formatted_advance_paid, self.name, formatted_order_total)) - + frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid) @property @@ -646,11 +647,11 @@ def set_balance_in_account_currency(gl_dict, account_currency=None, conversion_r else flt(gl_dict.credit / conversion_rate, 2) -def get_advance_journal_entries(party_type, party, party_account, amount_field, +def get_advance_journal_entries(party_type, party, party_account, amount_field, order_doctype, order_list, include_unallocated=True): - + dr_or_cr = "credit_in_account_currency" if party_type=="Customer" else "debit_in_account_currency" - + conditions = [] if include_unallocated: conditions.append("ifnull(t2.reference_name, '')=''") @@ -659,12 +660,12 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field, order_condition = ', '.join(['%s'] * len(order_list)) conditions.append(" (t2.reference_type = '{0}' and ifnull(t2.reference_name, '') in ({1}))"\ .format(order_doctype, order_condition)) - + reference_condition = " and (" + " or ".join(conditions) + ")" if conditions else "" - + journal_entries = frappe.db.sql(""" select - "Journal Entry" as reference_type, t1.name as reference_name, + "Journal Entry" as reference_type, t1.name as reference_name, t1.remark as remarks, t2.{0} as amount, t2.name as reference_row, t2.reference_name as against_order from @@ -677,10 +678,10 @@ def get_advance_journal_entries(party_type, party, party_account, amount_field, and (ifnull(t2.reference_name, '')='' {2}) order by t1.posting_date""".format(amount_field, dr_or_cr, reference_condition), [party_account, party_type, party] + order_list, as_dict=1) - + return list(journal_entries) - -def get_advance_payment_entries(party_type, party, party_account, + +def get_advance_payment_entries(party_type, party, party_account, order_doctype, order_list=None, include_unallocated=True, against_all_orders=False): party_account_field = "paid_from" if party_type == "Customer" else "paid_to" payment_type = "Receive" if party_type == "Customer" else "Pay" @@ -693,28 +694,28 @@ def get_advance_payment_entries(party_type, party, party_account, else: reference_condition = "" order_list = [] - + payment_entries_against_order = frappe.db.sql(""" select "Payment Entry" as reference_type, t1.name as reference_name, t1.remarks, t2.allocated_amount as amount, t2.name as reference_row, t2.reference_name as against_order, t1.posting_date - from `tabPayment Entry` t1, `tabPayment Entry Reference` t2 + from `tabPayment Entry` t1, `tabPayment Entry Reference` t2 where t1.name = t2.parent and t1.{0} = %s and t1.payment_type = %s and t1.party_type = %s and t1.party = %s and t1.docstatus = 1 and t2.reference_doctype = %s {1} - """.format(party_account_field, reference_condition), + """.format(party_account_field, reference_condition), [party_account, payment_type, party_type, party, order_doctype] + order_list, as_dict=1) - + if include_unallocated: unallocated_payment_entries = frappe.db.sql(""" - select "Payment Entry" as reference_type, name as reference_name, + select "Payment Entry" as reference_type, name as reference_name, remarks, unallocated_amount as amount from `tabPayment Entry` where {0} = %s and party_type = %s and party = %s and payment_type = %s and docstatus = 1 and unallocated_amount > 0 """.format(party_account_field), (party_account, party_type, party, payment_type), as_dict=1) - + return list(payment_entries_against_order) + list(unallocated_payment_entries) \ No newline at end of file diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index f0f2312f42d..88acfb7c176 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -28,7 +28,7 @@ class BuyingController(StockController): super(BuyingController, self).validate() if getattr(self, "supplier", None) and not self.supplier_name: self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name") - self.is_item_table_empty() + self.set_qty_as_per_stock_uom() self.validate_stock_or_nonstock_items() self.validate_warehouse() @@ -129,7 +129,7 @@ class BuyingController(StockController): valuation_amount_adjustment -= item.item_tax_amount self.round_floats_in(item) - if flt(item.conversion_factor)==0: + if flt(item.conversion_factor)==0.0: item.conversion_factor = get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0 qty_in_stock_uom = flt(item.qty * item.conversion_factor) @@ -276,10 +276,6 @@ class BuyingController(StockController): return self._sub_contracted_items - def is_item_table_empty(self): - if not len(self.get("items")): - frappe.throw(_("Item table can not be blank")) - def set_qty_as_per_stock_uom(self): for d in self.get("items"): if d.meta.get_field("stock_qty"): diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 254d9a6fa55..6ae5bbea81a 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import flt, comma_or -from frappe import msgprint, _, throw +from frappe import _ from frappe.model.document import Document def validate_status(status, options): @@ -135,15 +135,12 @@ class StatusUpdater(Document): item['idx'] = d.idx item['target_ref_field'] = args['target_ref_field'].replace('_', ' ') - if not item[args['target_ref_field']]: - msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code)) - elif args.get('no_tolerance'): + # if not item[args['target_ref_field']]: + # msgprint(_("Note: System will not check over-delivery and over-booking for Item {0} as quantity or amount is 0").format(item.item_code)) + if args.get('no_tolerance'): item['reduce_by'] = item[args['target_field']] - item[args['target_ref_field']] if item['reduce_by'] > .01: - msgprint(_("Allowance for over-{0} crossed for Item {1}") - .format(args["overflow_type"], item.item_code)) - throw(_("{0} must be reduced by {1} or you should increase overflow tolerance") - .format(_(item.target_ref_field.title()), item["reduce_by"])) + self.limits_crossed_error(args, item) else: self.check_overflow_with_tolerance(item, args) @@ -162,10 +159,20 @@ class StatusUpdater(Document): item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100) item['reduce_by'] = item[args['target_field']] - item['max_allowed'] - msgprint(_("Allowance for over-{0} crossed for Item {1}.") - .format(args["overflow_type"], item["item_code"])) - throw(_("{0} must be reduced by {1} or you should increase overflow tolerance") - .format(_(item["target_ref_field"].title()), item["reduce_by"])) + self.limits_crossed_error(args, item) + + def limits_crossed_error(self, args, item): + '''Raise exception for limits crossed''' + frappe.throw(_('This document is over limit by {0} {1} for item {4}. Are you making another {3} against the same {2}?') + .format( + frappe.bold(_(item["target_ref_field"].title())), + frappe.bold(item["reduce_by"]), + frappe.bold(_(args.get('target_dt'))), + frappe.bold(_(self.doctype)), + frappe.bold(item.get('item_code')) + ) + '

' + + _('To allow over-billing or over-ordering, update "Allowance" in Stock Settings or the Item.'), + title = _('Limit Crossed')) def update_qty(self, update_modified=True): """Updates qty or amount at row level diff --git a/erpnext/demo/data/item.json b/erpnext/demo/data/item.json index 30436d11e74..d8d45848794 100644 --- a/erpnext/demo/data/item.json +++ b/erpnext/demo/data/item.json @@ -92,7 +92,8 @@ "image": null, "item_code": "Base Plate", "item_group": "Raw Material", - "item_name": "Base Plate" + "item_name": "Base Plate", + "is_sub_contracted_item": 1 }, { "default_supplier": "Scott Ties", diff --git a/erpnext/demo/demo.py b/erpnext/demo/demo.py index 3ca8eb933c1..ff0f1847321 100644 --- a/erpnext/demo/demo.py +++ b/erpnext/demo/demo.py @@ -4,7 +4,7 @@ import frappe, sys import erpnext import frappe.utils from erpnext.demo.setup_data import setup_data -from erpnext.demo.user import hr, sales +from erpnext.demo.user import hr, sales, purchase def make(domain='Manufacturing'): frappe.flags.domain = domain @@ -42,7 +42,7 @@ def simulate(): hr.work() sales.work() - # run_purchase() + purchase.work() # run_manufacturing() # run_stock() # run_accounts() diff --git a/erpnext/demo/setup_data.py b/erpnext/demo/setup_data.py index bfaee4754bc..6492152f881 100644 --- a/erpnext/demo/setup_data.py +++ b/erpnext/demo/setup_data.py @@ -300,3 +300,8 @@ def setup_user_roles(): user = frappe.get_doc('User', 'GabrielleLoftus@example.com') user.add_roles('Sales User', 'Sales Manager', 'Accounts User') frappe.db.set_global('demo_sales_user_2', user.name) + + if not frappe.db.get_global('demo_purchase_user'): + user = frappe.get_doc('User', 'MichalSobczak@example.com') + user.add_roles('Purchase User', 'Purchase Manager', 'Accounts User') + frappe.db.set_global('demo_purchase_user', user.name) diff --git a/erpnext/demo/user/purchase.py b/erpnext/demo/user/purchase.py index cf2735813e2..58da9d333c7 100644 --- a/erpnext/demo/user/purchase.py +++ b/erpnext/demo/user/purchase.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, random -from frappe.utils.make_random import how_many, can_make, get_random +from frappe.utils.make_random import how_many, get_random from frappe.desk import query_report from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.party import get_party_account_currency @@ -13,30 +13,40 @@ from erpnext.stock.doctype.material_request.material_request import make_request from erpnext.buying.doctype.request_for_quotation.request_for_quotation import \ make_supplier_quotation as make_quotation_from_rfq -def run_purchase(current_date): +def work(): + frappe.set_user(frappe.db.get_global('demo_purchase_user')) + if random.random() < 0.3: report = "Items To Be Requested" - for row in query_report.run(report)["result"][:how_many("Material Request")]: + for row in query_report.run(report)["result"][:random.randint(1, 5)]: item_code, qty = row[0], abs(row[-1]) mr = make_material_request(item_code, qty) if random.random() < 0.3: - for mr in frappe.get_all('Material Request', filters={'material_request_type': 'Purchase', 'status': 'Open'}): - rfq = make_request_for_quotation(mr.name) - rfq.transaction_date = frappe.flags.current_date - add_suppliers(rfq) - rfq.save() - rfq.submit() + for mr in frappe.get_all('Material Request', + filters={'material_request_type': 'Purchase', 'status': 'Open'}, + limit=random.randint(1,6)): + if not frappe.get_all('Request for Quotation', + filters={'material_request': mr.name}, limit=1): + rfq = make_request_for_quotation(mr.name) + rfq.transaction_date = frappe.flags.current_date + add_suppliers(rfq) + rfq.save() + rfq.submit() - # Make suppier quotation from RFQ against each supplier. + # Make suppier quotation from RFQ against each supplier. if random.random() < 0.3: - for supplier_quotation in frappe.get_all('Request for Quotation', {'status': 'Open'}): - rfq = frappe.get_doc('Request for Quotation', rfq.name) - for supplier in rfq.suppliers: - supplier_quotation = make_quotation_from_rfq(rfq.name, supplier.supplier) - supplier_quotation.save() - supplier_quotation.submit() + for rfq in frappe.get_all('Request for Quotation', + filters={'status': 'Open'}, limit=random.randint(1, 6)): + if not frappe.get_all('Supplier Quotation', + filters={'request_for_quotation': rfq.name}, limit=1): + rfq = frappe.get_doc('Request for Quotation', rfq.name) + + for supplier in rfq.suppliers: + supplier_quotation = make_quotation_from_rfq(rfq.name, supplier.supplier) + supplier_quotation.save() + supplier_quotation.submit() # get supplier details supplier = get_random("Supplier") @@ -49,14 +59,14 @@ def run_purchase(current_date): exchange_rate = get_exchange_rate(party_account_currency, company_currency) # make supplier quotations - if can_make("Supplier Quotation"): + if random.random() < 0.3: from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation report = "Material Requests for which Supplier Quotations are not created" for row in query_report.run(report)["result"][:how_many("Supplier Quotation")]: if row[0] != "'Total'": sq = frappe.get_doc(make_supplier_quotation(row[0])) - sq.transaction_date = current_date + sq.transaction_date = frappe.flags.current_date sq.supplier = supplier sq.currency = party_account_currency or company_currency sq.conversion_rate = exchange_rate @@ -65,7 +75,7 @@ def run_purchase(current_date): frappe.db.commit() # make purchase orders - if can_make("Purchase Order"): + if random.random() < 0.3: from erpnext.stock.doctype.material_request.material_request import make_purchase_order report = "Requested Items To Be Ordered" for row in query_report.run(report)["result"][:how_many("Purchase Order")]: @@ -74,13 +84,13 @@ def run_purchase(current_date): po.supplier = supplier po.currency = party_account_currency or company_currency po.conversion_rate = exchange_rate - po.transaction_date = current_date + po.transaction_date = frappe.flags.current_date po.insert() po.submit() frappe.db.commit() - if can_make("Subcontract"): - make_subcontract(current_date) + if random.random() < 0.3: + make_subcontract() def make_material_request(item_code, qty): mr = frappe.new_doc("Material Request") diff --git a/erpnext/stock/doctype/material_request/material_request_dashboard.py b/erpnext/stock/doctype/material_request/material_request_dashboard.py index aa341a811bd..7ed10401e2b 100644 --- a/erpnext/stock/doctype/material_request/material_request_dashboard.py +++ b/erpnext/stock/doctype/material_request/material_request_dashboard.py @@ -3,9 +3,6 @@ from frappe import _ data = { 'docstatus': 1, 'fieldname': 'material_request', - 'non_standard_fieldnames': { - 'Purchase Order': 'prevdoc_detail_docname', - }, 'transactions': [ { 'label': _('Related Documents'),