diff --git a/erpnext/__init__.py b/erpnext/__init__.py index fa3fcc2cce..405274a144 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from erpnext.hooks import regional_overrides -__version__ = '9.0.4' +__version__ = '9.0.6' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index f7e40231e1..b553a42c46 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -12,8 +12,8 @@ from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status class JournalEntry(AccountsController): - def __init__(self, arg1, arg2=None): - super(JournalEntry, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(JournalEntry, self).__init__(*args, **kwargs) def get_feed(self): return self.voucher_type diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index a564d92338..c12aa50434 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -22,8 +22,8 @@ form_grid_templates = { } class PurchaseInvoice(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseInvoice, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseInvoice, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Invoice Item', 'target_dt': 'Purchase Order Item', diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 2b3459ad27..dd10977665 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -417,6 +417,7 @@ def make_contact(args,customer): 'link_doctype': 'Customer', 'link_name': customer }) + doc.flags.ignore_mandatory = True doc.save(ignore_permissions=True) def make_address(args, customer): @@ -441,6 +442,7 @@ def make_address(args, customer): address.is_primary_address = 1 address.is_shipping_address = 1 address.update(args) + address.flags.ignore_mandatory = True address.save(ignore_permissions = True) def make_email_queue(email_queue): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 678988db6e..515ca6415b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -27,8 +27,8 @@ form_grid_templates = { } class SalesInvoice(SellingController): - def __init__(self, arg1, arg2=None): - super(SalesInvoice, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SalesInvoice, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Sales Invoice Item', 'target_field': 'billed_amt', diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index be0b6f7b72..57a8a186b9 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -113,6 +113,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }); this.page.add_menu_item(__("Sync Offline Invoices"), function () { + me.freeze_screen = true; me.sync_sales_invoice() }); @@ -1684,6 +1685,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ set_interval_for_si_sync: function () { var me = this; setInterval(function () { + me.freeze_screen = false; me.sync_sales_invoice() }, 60000) }, @@ -1697,9 +1699,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.freeze = this.customer_doc.display } + freeze_screen = this.freeze_screen || false; + if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) { frappe.call({ method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice", + freeze: freeze_screen, args: { doc_list: me.si_docs, email_queue_list: me.email_queue_list, diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index b86561b837..6bb6dc1660 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -69,7 +69,8 @@ def set_address_details(out, party, party_type, doctype=None, company=None): billing_address_field = "customer_address" if party_type == "Lead" \ else party_type.lower() + "_address" out[billing_address_field] = get_default_address(party_type, party.name) - out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field])) + if doctype: + out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field])) # address display out.address_display = get_address_display(out[billing_address_field]) @@ -78,7 +79,8 @@ def set_address_details(out, party, party_type, doctype=None, company=None): if party_type in ["Customer", "Lead"]: out.shipping_address_name = get_default_address(party_type, party.name, 'is_shipping_address') out.shipping_address = get_address_display(out["shipping_address_name"]) - out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) + if doctype: + out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) if doctype and doctype in ['Delivery Note', 'Sales Invoice']: out.update(get_company_address(company)) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index e2f5a9dca8..36cef4396b 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -20,8 +20,8 @@ form_grid_templates = { } class PurchaseOrder(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseOrder, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseOrder, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Order Item', 'target_dt': 'Material Request Item', diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 9719c22cf7..c538f7999f 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -15,8 +15,8 @@ from erpnext.exceptions import InvalidCurrency force_item_fields = ("item_group", "barcode", "brand", "stock_uom") class AccountsController(TransactionBase): - def __init__(self, arg1, arg2=None): - super(AccountsController, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(AccountsController, self).__init__(*args, **kwargs) @property def company_currency(self): @@ -213,9 +213,6 @@ class AccountsController(TransactionBase): if stock_qty != len(get_serial_nos(item.get('serial_no'))): item.set(fieldname, value) - elif fieldname == "conversion_factor" and not item.get("conversion_factor"): - item.set(fieldname, value) - if ret.get("pricing_rule"): # if user changed the discount percentage then set user's discount percentage ? item.set("discount_percentage", ret.get("discount_percentage")) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 9cc061677e..1f9051d433 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -61,7 +61,7 @@ class BuyingController(StockController): # set contact and address details for supplier, if they are not mentioned if getattr(self, "supplier", None): - self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions)) + self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions, doctype=self.doctype, company=self.company)) self.set_missing_item_details(for_validate) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d881f18b33..c1028a598d 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -49,7 +49,8 @@ class SellingController(StockController): if getattr(self, "customer", None): from erpnext.accounts.party import _get_party_details party_details = _get_party_details(self.customer, - ignore_permissions=self.flags.ignore_permissions) + ignore_permissions=self.flags.ignore_permissions, + doctype=self.doctype, company=self.company) if not self.meta.get_field("sales_team"): party_details.pop("sales_team") diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 4251cae954..970fd570ff 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -42,10 +42,28 @@ class Opportunity(TransactionBase): if not self.with_items: self.items = [] - def make_new_lead_if_required(self): """Set lead against new opportunity""" if not (self.lead or self.customer) and self.contact_email: + # check if customer is already created agains the self.contact_email + customer = frappe.db.sql("""select + distinct `tabDynamic Link`.link_name as customer + from + `tabContact`, + `tabDynamic Link` + where `tabContact`.email_id='{0}' + and + `tabContact`.name=`tabDynamic Link`.parent + and + ifnull(`tabDynamic Link`.link_name, '')<>'' + and + `tabDynamic Link`.link_doctype='Customer' + """.format(self.contact_email), as_dict=True) + if customer and customer[0].customer: + self.customer = customer[0].customer + self.enquiry_from = "Customer" + return + lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email}) if not lead_name: sender_name = get_fullname(self.contact_email) diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py index 4cd20ea72d..61b583ce3b 100644 --- a/erpnext/crm/doctype/opportunity/test_opportunity.py +++ b/erpnext/crm/doctype/opportunity/test_opportunity.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import today +from erpnext.crm.doctype.lead.lead import make_customer from erpnext.crm.doctype.opportunity.opportunity import make_quotation import unittest @@ -25,12 +26,45 @@ class TestOpportunity(unittest.TestCase): doc = frappe.get_doc('Opportunity', doc.name) self.assertEquals(doc.status, "Quotation") + def test_make_new_lead_if_required(self): + args = { + "doctype": "Opportunity", + "contact_email":"new.opportunity@example.com", + "enquiry_type": "Sales", + "with_items": 0, + "transaction_date": today() + } + # new lead should be created against the new.opportunity@example.com + opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) + + self.assertTrue(opp_doc.lead) + self.assertEquals(opp_doc.enquiry_from, "Lead") + self.assertEquals(frappe.db.get_value("Lead", opp_doc.lead, "email_id"), + 'new.opportunity@example.com') + + # create new customer and create new contact against 'new.opportunity@example.com' + customer = make_customer(opp_doc.lead).insert(ignore_permissions=True) + frappe.get_doc({ + "doctype": "Contact", + "email_id": "new.opportunity@example.com", + "first_name": "_Test Opportunity Customer", + "links": [{ + "link_doctype": "Customer", + "link_name": customer.name + }] + }).insert(ignore_permissions=True) + + opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) + self.assertTrue(opp_doc.customer) + self.assertEquals(opp_doc.enquiry_from, "Customer") + self.assertEquals(opp_doc.customer, customer.name) + def make_opportunity(**args): args = frappe._dict(args) opp_doc = frappe.get_doc({ "doctype": "Opportunity", - "enquiry_from": "Customer" or args.enquiry_from, + "enquiry_from": args.enquiry_from or "Customer", "enquiry_type": "Sales", "with_items": args.with_items or 0, "transaction_date": today() diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 48ed7415d7..6d411cd1d7 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -11,7 +11,7 @@ app_email = "info@erpnext.com" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" -develop_version = '8.x.x-beta' +develop_version = '9.x.x-develop' error_report_email = "support@erpnext.com" diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 815e504447..1d57a2faa0 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -12,10 +12,6 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from erpnext.manufacturing.doctype.production_order.production_order import get_item_details class ProductionPlanningTool(Document): - def __init__(self, arg1, arg2=None): - super(ProductionPlanningTool, self).__init__(arg1, arg2) - self.item_dict = {} - def clear_table(self, table_name): self.set(table_name, []) @@ -398,6 +394,9 @@ class ProductionPlanningTool(Document): return bom_wise_item_details def make_items_dict(self, item_list): + if not getattr(self, "item_dict", None): + self.item_dict = {} + for i in item_list: self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]]) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 805587751a..8421c47c72 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -101,27 +101,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ return me.set_query_for_batch(doc, cdt, cdn) }); } - }, - onload: function() { - var me = this; - if(this.frm.doc.__islocal) { - var today = frappe.datetime.get_today(), - currency = frappe.defaults.get_user_default("currency"); - - $.each({ - currency: currency, - price_list_currency: currency, - status: "Draft", - is_subcontracted: "No", - }, function(fieldname, value) { - if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) - me.frm.set_value(fieldname, value); - }); - - if(this.frm.doc.company && !this.frm.doc.amended_from) { - this.frm.trigger("company"); - } - } if(this.frm.fields_dict["payment_terms_template"]){ this.frm.trigger("payment_terms_template"); @@ -157,11 +136,36 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ return { filters: filters - } + }; }); } + }, + onload: function() { + var me = this; this.setup_quality_inspection(); + + if(this.frm.doc.__islocal) { + var currency = frappe.defaults.get_user_default("currency"); + + let set_value = (fieldname, value) => { + if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) { + return me.frm.set_value(fieldname, value); + } + }; + + return frappe.run_serially([ + () => set_value('currency', currency), + () => set_value('price_list_currency', currency), + () => set_value('status', 'Draft'), + () => set_value('is_subcontracted', 'No'), + () => { + if(this.frm.doc.company && !this.frm.doc.amended_from) { + this.frm.trigger("company"); + } + } + ]); + } }, setup_quality_inspection: function() { @@ -199,13 +203,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, onload_post_render: function() { - var me = this; if(this.frm.doc.__islocal && !(this.frm.doc.taxes || []).length && !(this.frm.doc.__onload ? this.frm.doc.__onload.load_after_mapping : false)) { - this.apply_default_taxes(); + frappe.after_ajax(() => this.apply_default_taxes()); } else if(this.frm.doc.__islocal && this.frm.doc.company && this.frm.doc["items"] && !this.frm.doc.is_pos) { - me.calculate_taxes_and_totals(); + frappe.after_ajax(() => this.calculate_taxes_and_totals()); } if(frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "item_code")) { this.setup_item_selector(); @@ -383,7 +386,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ var company_currency = me.get_company_currency(); var company_doc = frappe.get_doc(":Company", me.frm.doc.company); - if (!me.frm.doc.currency || me.frm.doc.currency != company_currency) { + if (!me.frm.doc.currency) { me.frm.set_value("currency", company_currency); } diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index 88178f42ce..7c274f18db 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -86,6 +86,10 @@ erpnext.setup.slides_settings = [ }); }, validate: function() { + if ((this.values.company_name || "").toLowerCase() == "company") { + frappe.msgprint(__("Company Name cannot be Company")); + return false; + } if (!this.values.company_abbr) { return false; } @@ -135,10 +139,6 @@ erpnext.setup.slides_settings = [ frappe.msgprint(__("Please enter valid Financial Year Start and End Dates")); return false; } - if ((this.values.company_name || "").toLowerCase() == "company") { - frappe.msgprint(__("Company Name cannot be Company")); - return false; - } return true; }, diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 3e2414e665..69e3d2fb9f 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -96,7 +96,17 @@ erpnext.SerialNoBatchSelector = Class.extend({ if(this.show_dialog) { let d = this.item; - this.dialog.set_value('serial_no', d.serial_no); + if (d.has_serial_no && d.serial_no) { + this.dialog.set_value('serial_no', d.serial_no); + } else if (d.batch_no) { + this.dialog.fields_dict.batches.df.data.push({ + 'batch_no': d.batch_no, + 'actual_qty': d.actual_qty, + 'selected_qty': d.qty + }); + + this.dialog.fields_dict.batches.grid.refresh(); + } } this.dialog.show(); @@ -116,8 +126,10 @@ erpnext.SerialNoBatchSelector = Class.extend({ } values.batches.map((batch, i) => { if(!batch.selected_qty || batch.selected_qty === 0 ) { - frappe.throw(__("Please select quantity on row " + (i+1))); - return false; + if (!this.show_dialog) { + frappe.throw(__("Please select quantity on row " + (i+1))); + return false; + } } }); return true; @@ -125,9 +137,11 @@ erpnext.SerialNoBatchSelector = Class.extend({ } else { let serial_nos = values.serial_no || ''; if (!serial_nos || !serial_nos.replace(/\s/g, '').length) { - frappe.throw(__("Please enter serial numbers for serialized item " - + values.item_code)); - return false; + if (!this.show_dialog) { + frappe.throw(__("Please enter serial numbers for serialized item " + + values.item_code)); + return false; + } } return true; } diff --git a/erpnext/schools/doctype/student_applicant/student_applicant.py b/erpnext/schools/doctype/student_applicant/student_applicant.py index 081fa065db..aeeffcedac 100644 --- a/erpnext/schools/doctype/student_applicant/student_applicant.py +++ b/erpnext/schools/doctype/student_applicant/student_applicant.py @@ -13,7 +13,6 @@ class StudentApplicant(Document): if self.student_admission: naming_series = frappe.db.get_value('Student Admission', self.student_admission, 'naming_series_for_student_applicant') - print(naming_series) if naming_series: self.naming_series = naming_series diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py index 720247da56..9f730f4878 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.py +++ b/erpnext/selling/doctype/installation_note/installation_note.py @@ -12,8 +12,8 @@ from erpnext.stock.utils import get_valid_serial_nos from erpnext.utilities.transaction_base import TransactionBase class InstallationNote(TransactionBase): - def __init__(self, arg1, arg2=None): - super(InstallationNote, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(InstallationNote, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Installation Note Item', 'target_dt': 'Delivery Note Item', diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 1cdd840428..f0cce5ffb7 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -32,7 +32,7 @@ class Quotation(SellingController): self.validate_valid_till() if self.items: self.with_items = 1 - + def validate_valid_till(self): if self.valid_till and self.valid_till < self.transaction_date: frappe.throw(_("Valid till date cannot be before transaction date")) @@ -79,15 +79,10 @@ class Quotation(SellingController): else: frappe.throw(_("Cannot set as Lost as Sales Order is made.")) - def check_item_table(self): - if not self.get('items'): - frappe.throw(_("Please enter item details")) - def on_submit(self): - self.check_item_table() - # Check for Approving Authority - frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total, self) + frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, + self.company, self.base_grand_total, self) #update enquiry status self.update_opportunity() diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 8720482549..98333c495e 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -22,8 +22,8 @@ form_grid_templates = { class WarehouseRequired(frappe.ValidationError): pass class SalesOrder(SellingController): - def __init__(self, arg1, arg2=None): - super(SalesOrder, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SalesOrder, self).__init__(*args, **kwargs) def validate(self): super(SalesOrder, self).validate() @@ -696,7 +696,8 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc= "contact_display", "contact_mobile", "contact_email", - "contact_person" + "contact_person", + "taxes_and_charges" ], "validation": { "docstatus": ["=", 1] diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js index 1b67ff2b72..f9045b5454 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.js +++ b/erpnext/selling/page/point_of_sale/point_of_sale.js @@ -89,6 +89,7 @@ erpnext.pos.PointOfSale = class PointOfSale { this.cart = new POSCart({ frm: this.frm, wrapper: this.wrapper.find('.cart-container'), + pos_profile: this.pos_profile, events: { on_customer_change: (customer) => this.frm.set_value('customer', customer), on_field_change: (item_code, field, value) => { @@ -196,6 +197,7 @@ erpnext.pos.PointOfSale = class PointOfSale { this.update_item_in_frm(item) .then(() => { // update cart + this.remove_item_from_cart(item); this.update_cart_data(item); }); }, true); @@ -215,12 +217,18 @@ erpnext.pos.PointOfSale = class PointOfSale { return this.frm.script_manager .trigger('qty', item.doctype, item.name) .then(() => { - if (field === 'qty' && value === 0) { - frappe.model.clear_doc(item.doctype, item.name); + if (field === 'qty') { + this.remove_item_from_cart(item); } }); } + remove_item_from_cart(item) { + if (item.qty === 0) { + frappe.model.clear_doc(item.doctype, item.name); + } + } + make_payment_modal() { this.payment = new Payment({ frm: this.frm, @@ -363,10 +371,11 @@ erpnext.pos.PointOfSale = class PointOfSale { }; class POSCart { - constructor({frm, wrapper, events}) { + constructor({frm, wrapper, pos_profile, events}) { this.frm = frm; this.wrapper = wrapper; this.events = events; + this.pos_profile = pos_profile; this.make(); this.bind_events(); } @@ -514,6 +523,7 @@ class POSCart { } make_customer_field() { + let customer = this.frm.doc.customer || this.pos_profile['customer']; this.customer_field = frappe.ui.form.make_control({ df: { fieldtype: 'Link', @@ -521,7 +531,6 @@ class POSCart { fieldname: 'customer', options: 'Customer', reqd: 1, - default: this.frm.doc.customer, onchange: () => { this.events.on_customer_change(this.customer_field.get_value()); } @@ -529,6 +538,10 @@ class POSCart { parent: this.wrapper.find('.customer-field'), render_input: true }); + + if (customer) { + this.customer_field.set_value(customer); + } } make_numpad() { @@ -919,7 +932,7 @@ class POSItems { } if(batch_no) { this.events.update_cart(items[0].item_code, - 'batch_no', serial_no); + 'batch_no', batch_no); this.search_field.set_value(''); } }); diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index c85a541d84..8d1fb3d4a6 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -16,14 +16,13 @@ user_specific_content = ["calendar_events", "todo_list"] from frappe.model.document import Document class EmailDigest(Document): - def __init__(self, arg1, arg2=None): - super(EmailDigest, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(EmailDigest, self).__init__(*args, **kwargs) self.from_date, self.to_date = self.get_from_to_date() self.set_dates() self._accounts = {} - self.currency = frappe.db.get_value("Company", self.company, - "default_currency") + self.currency = frappe.db.get_value("Company", self.company, "default_currency") def get_users(self): """get list of users""" diff --git a/erpnext/setup/setup_wizard/healthcare.py b/erpnext/setup/setup_wizard/healthcare.py index ebc644e87b..43a02371f4 100644 --- a/erpnext/setup/setup_wizard/healthcare.py +++ b/erpnext/setup/setup_wizard/healthcare.py @@ -191,21 +191,21 @@ def create_healthcare_item_groups(): def create_lab_test_items(): records = [ {"doctype": "Item", "item_code": "MCH", "item_name": "MCH", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "LDL", "item_name": "LDL", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "GTT", "item_name": "GTT", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "HDL", "item_name": "HDL", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "BILT", "item_name": "BILT", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "BILD", "item_name": "BILD", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "BP", "item_name": "BP", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, {"doctype": "Item", "item_code": "BS", "item_name": "BS", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1} + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1} ] insert_record(records) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index f5a99afbd2..dd00398695 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -21,8 +21,8 @@ form_grid_templates = { } class DeliveryNote(SellingController): - def __init__(self, arg1, arg2=None): - super(DeliveryNote, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(DeliveryNote, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Delivery Note Item', 'target_dt': 'Sales Order Item', diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 2d089c4419..e49f9937a5 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -19,8 +19,8 @@ form_grid_templates = { } class PurchaseReceipt(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseReceipt, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseReceipt, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Receipt Item', 'target_dt': 'Purchase Order Item', diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index c39efa06f7..80c93ef434 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -20,8 +20,8 @@ class SerialNoNotExistsError(ValidationError): pass class SerialNoDuplicateError(ValidationError): pass class SerialNo(StockController): - def __init__(self, arg1, arg2=None): - super(SerialNo, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SerialNo, self).__init__(*args, **kwargs) self.via_stock_ledger = False def validate(self): diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 360ebca11e..0f91e43223 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -14,8 +14,8 @@ class OpeningEntryAccountError(frappe.ValidationError): pass class EmptyStockReconciliationItemsError(frappe.ValidationError): pass class StockReconciliation(StockController): - def __init__(self, arg1, arg2=None): - super(StockReconciliation, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(StockReconciliation, self).__init__(*args, **kwargs) self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] def validate(self): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 0b92c250aa..539e8a5667 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -165,14 +165,13 @@ def get_basic_details(args, item): warehouse = user_default_warehouse or item.default_warehouse or args.warehouse #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master - if args.get('doctype') in ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: - uom = item.sales_uom if item.sales_uom else item.stock_uom - elif args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']: - uom = item.purchase_uom if item.purchase_uom else item.stock_uom - else: - uom = item.stock_uom - - args.uom = uom + if not args.uom: + if args.get('doctype') in ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: + args.uom = item.sales_uom if item.sales_uom else item.stock_uom + elif args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']: + args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom + else: + args.uom = item.stock_uom out = frappe._dict({ "item_code": item.name, @@ -188,7 +187,7 @@ def get_basic_details(args, item): "batch_no": None, "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in item.get("taxes")))), - "uom": uom, + "uom": args.uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", "qty": args.qty or 1.0, "stock_qty": args.qty or 1.0,