diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.js b/erpnext/accounts/doctype/share_transfer/share_transfer.js index 446ae689fc..364ca6fd28 100644 --- a/erpnext/accounts/doctype/share_transfer/share_transfer.js +++ b/erpnext/accounts/doctype/share_transfer/share_transfer.js @@ -16,7 +16,7 @@ frappe.ui.form.on('Share Transfer', { }; }; }); - if (frm.doc.docstatus == 1) { + if (frm.doc.docstatus == 1 && frm.doc.equity_or_liability_account && frm.doc.asset_account) { frm.add_custom_button(__('Create Journal Entry'), function () { erpnext.share_transfer.make_jv(frm); }); diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.json b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.json index ae2aa542f5..b40243cb75 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.json +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.json @@ -1,13 +1,13 @@ { "add_total_row": 0, "creation": "2019-09-23 16:35:02.836134", - "disable_prepared_report": 0, + "disable_prepared_report": 1, "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 0, "is_standard": "Yes", - "modified": "2019-09-23 16:35:02.836134", + "modified": "2019-10-22 13:00:31.539726", "modified_by": "Administrator", "module": "Assets", "name": "Fixed Asset Register", diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 2c9e48a06c..f395499ad6 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ +from frappe.utils import cstr def execute(filters=None): filters = frappe._dict(filters or {}) @@ -149,12 +150,12 @@ def get_finance_book_value_map(finance_book=''): FROM `tabAsset Finance Book` WHERE parentfield='finance_books' - AND finance_book=%s''', (finance_book))) + AND ifnull(finance_book, '')=%s''', cstr(finance_book))) def get_purchase_receipt_supplier_map(): return frappe._dict(frappe.db.sql(''' Select pr.name, pr.supplier - FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri + FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri WHERE pri.parent = pr.name AND pri.is_fixed_asset=1 @@ -164,7 +165,7 @@ def get_purchase_receipt_supplier_map(): def get_purchase_invoice_supplier_map(): return frappe._dict(frappe.db.sql(''' Select pi.name, pi.supplier - FROM `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pii + FROM `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pii WHERE pii.parent = pi.name AND pii.is_fixed_asset=1 diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index ff0b65b7be..4506db6405 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -589,6 +589,23 @@ class TestPurchaseOrder(unittest.TestCase): frappe.db.set_value("Accounts Settings", "Accounts Settings", "unlink_advance_payment_on_cancelation_of_order", 0) + def test_schedule_date(self): + po = create_purchase_order(do_not_submit=True) + po.schedule_date = None + po.append("items", { + "item_code": "_Test Item", + "qty": 1, + "rate": 100, + "schedule_date": add_days(nowdate(), 5) + }) + po.save() + self.assertEqual(po.schedule_date, add_days(nowdate(), 1)) + + po.items[0].schedule_date = add_days(nowdate(), 2) + po.save() + self.assertEqual(po.schedule_date, add_days(nowdate(), 2)) + + def make_pr_against_po(po, received_qty=0): pr = make_purchase_receipt(po) pr.get("items")[0].qty = received_qty or 5 diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 9d37df0406..0dde898005 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -695,8 +695,10 @@ class BuyingController(StockController): def validate_schedule_date(self): if not self.get("items"): return - if not self.schedule_date: - self.schedule_date = min([d.schedule_date for d in self.get("items")]) + + earliest_schedule_date = min([d.schedule_date for d in self.get("items")]) + if earliest_schedule_date: + self.schedule_date = earliest_schedule_date if self.schedule_date: for d in self.get('items'): diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py index bd980374b6..3be08a2757 100644 --- a/erpnext/erpnext_integrations/connectors/shopify_connection.py +++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py @@ -29,7 +29,8 @@ def sync_sales_order(order, request_id=None): validate_item(order, shopify_settings) create_order(order, shopify_settings) except Exception as e: - make_shopify_log(status="Error", message=e.message, exception=False) + make_shopify_log(status="Error", exception=e) + else: make_shopify_log(status="Success") @@ -42,9 +43,9 @@ def prepare_sales_invoice(order, request_id=None): sales_order = get_sales_order(cstr(order['id'])) if sales_order: create_sales_invoice(order, shopify_settings, sales_order) - make_shopify_log(status="Success") - except Exception: - make_shopify_log(status="Error", exception=True) + make_shopify_log(status="Success") + except Exception as e: + make_shopify_log(status="Error", exception=e, rollback=True) def prepare_delivery_note(order, request_id=None): frappe.set_user('Administrator') @@ -56,8 +57,8 @@ def prepare_delivery_note(order, request_id=None): if sales_order: create_delivery_note(order, shopify_settings, sales_order) make_shopify_log(status="Success") - except Exception: - make_shopify_log(status="Error", exception=True) + except Exception as e: + make_shopify_log(status="Error", exception=e, rollback=True) def get_sales_order(shopify_order_id): sales_order = frappe.db.get_value("Sales Order", filters={"shopify_order_id": shopify_order_id}) @@ -97,7 +98,7 @@ def create_sales_order(shopify_order, shopify_settings, company=None): message = 'Following items are exists in order but relevant record not found in Product master' message += "\n" + ", ".join(product_not_exists) - make_shopify_log(status="Error", message=message, exception=True) + make_shopify_log(status="Error", exception=e, rollback=True) return '' diff --git a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py index 0c821e031d..7d3f572978 100644 --- a/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py +++ b/erpnext/erpnext_integrations/doctype/shopify_log/shopify_log.py @@ -12,23 +12,38 @@ class ShopifyLog(Document): pass -def make_shopify_log(status="Queued", message=None, exception=False): +def make_shopify_log(status="Queued", exception=None, rollback=False): # if name not provided by log calling method then fetch existing queued state log + make_new = False + if not frappe.flags.request_id: - return + make_new = True - log = frappe.get_doc("Shopify Log", frappe.flags.request_id) - - if exception: + if rollback: frappe.db.rollback() - log = frappe.get_doc({"doctype":"Shopify Log"}).insert(ignore_permissions=True) - log.message = message if message else '' + if make_new: + log = frappe.get_doc({"doctype":"Shopify Log"}).insert(ignore_permissions=True) + else: + log = log = frappe.get_doc("Shopify Log", frappe.flags.request_id) + + log.message = get_message(exception) log.traceback = frappe.get_traceback() log.status = status log.save(ignore_permissions=True) frappe.db.commit() +def get_message(exception): + message = None + + if hasattr(exception, 'message'): + message = exception.message + elif hasattr(exception, '__str__'): + message = e.__str__() + else: + message = "Something went wrong while syncing" + return message + def dump_request_data(data, event="create/order"): event_mapper = { "orders/create": get_webhook_address(connector_name='shopify_connection', method="sync_sales_order", exclude_uri=True), @@ -43,11 +58,11 @@ def dump_request_data(data, event="create/order"): }).insert(ignore_permissions=True) frappe.db.commit() - frappe.enqueue(method=event_mapper[event], queue='short', timeout=300, is_async=True, + frappe.enqueue(method=event_mapper[event], queue='short', timeout=300, is_async=True, **{"order": data, "request_id": log.name}) @frappe.whitelist() def resync(method, name, request_data): frappe.db.set_value("Shopify Log", name, "status", "Queued", update_modified=False) - frappe.enqueue(method=method, queue='short', timeout=300, is_async=True, + frappe.enqueue(method=method, queue='short', timeout=300, is_async=True, **{"order": json.loads(request_data), "request_id": name}) diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py index e2f6d497d2..a4332b199e 100644 --- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py +++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py @@ -30,13 +30,9 @@ class ShopifySettings(Document): # url = get_shopify_url('admin/webhooks.json', self) created_webhooks = [d.method for d in self.webhooks] url = get_shopify_url('admin/api/2019-04/webhooks.json', self) - print('url', url) for method in webhooks: - print('method', method) session = get_request_session() - print('session', session) try: - print(get_header(self)) d = session.post(url, data=json.dumps({ "webhook": { "topic": method, @@ -44,7 +40,6 @@ class ShopifySettings(Document): "format": "json" } }), headers=get_header(self)) - print('d', d.json()) d.raise_for_status() self.update_webhook_table(method, d.json()) except Exception as e: @@ -67,7 +62,6 @@ class ShopifySettings(Document): self.remove(d) def update_webhook_table(self, method, res): - print('update') self.append("webhooks", { "webhook_id": res['webhook']['id'], "method": method @@ -75,7 +69,6 @@ class ShopifySettings(Document): def get_shopify_url(path, settings): if settings.app_type == "Private": - print(settings.api_key, settings.get_password('password'), settings.shopify_url, path) return 'https://{}:{}@{}/{}'.format(settings.api_key, settings.get_password('password'), settings.shopify_url, path) else: return 'https://{}/{}'.format(settings.shopify_url, path) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index eb01b8c81e..225ae29429 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -35,7 +35,8 @@ class BOM(WebsiteGenerator): # name can be BOM/ITEM/001, BOM/ITEM/001-1, BOM-ITEM-001, BOM-ITEM-001-1 # split by item - names = [name.split(self.item)[-1][1:] for name in names] + names = [name.split(self.item, 1) for name in names] + names = [d[-1][1:] for d in filter(lambda x: len(x) > 1 and x[-1], names)] # split by (-) if cancelled names = [cint(name.split('-')[-1]) for name in names] diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 78e7b4abb8..ccc48e19b3 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -682,10 +682,10 @@ "label": "Additional Discount and Coupon Code" }, { - "fieldname": "coupon_code", - "fieldtype": "Link", - "label": "Coupon Code", - "options": "Coupon Code" + "fieldname": "coupon_code", + "fieldtype": "Link", + "label": "Coupon Code", + "options": "Coupon Code" }, { "default": "Grand Total", @@ -1185,6 +1185,7 @@ "default": "0", "fieldname": "skip_delivery_note", "fieldtype": "Check", + "hidden": 1, "label": "Skip Delivery Note", "print_hide": 1 } @@ -1192,7 +1193,7 @@ "icon": "fa fa-file-text", "idx": 105, "is_submittable": 1, - "modified": "2019-10-14 08:46:07.540565", + "modified": "2019-10-22 14:26:42.767189", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", @@ -1269,4 +1270,4 @@ "title_field": "title", "track_changes": 1, "track_seen": 1 -} +} \ No newline at end of file diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 758fb37211..7fa7d3b0b6 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -329,8 +329,8 @@ class StockEntry(StockController): if total_completed_qty > flt(completed_qty): job_card = frappe.db.get_value('Job Card', {'operation_id': d.name}, 'name') if not job_card: - frappe.throw(_("Work Order {0}: job card not found for the operation {1}") - .format(self.work_order, job_card)) + frappe.throw(_("Work Order {0}: Job Card not found for the operation {1}") + .format(self.work_order, d.operation)) work_order_link = frappe.utils.get_link_to_form('Work Order', self.work_order) job_card_link = frappe.utils.get_link_to_form('Job Card', job_card) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index e5ae70c8d4..68b8b502e5 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -39,6 +39,9 @@ def execute(filters=None): data = [] conversion_factors = {} + + _func = lambda x: x[1] + for (company, item, warehouse) in sorted(iwb_map): if item_map.get(item): qty_dict = iwb_map[(company, item, warehouse)] @@ -70,7 +73,9 @@ def execute(filters=None): 'latest_age': 0 } if fifo_queue: - fifo_queue = sorted(fifo_queue, key=lambda fifo_data: fifo_data[1]) + fifo_queue = sorted(filter(_func, fifo_queue), key=_func) + if not fifo_queue: continue + stock_ageing_data['average_age'] = get_average_age(fifo_queue, to_date) stock_ageing_data['earliest_age'] = date_diff(to_date, fifo_queue[0][1]) stock_ageing_data['latest_age'] = date_diff(to_date, fifo_queue[-1][1]) diff --git a/erpnext/stock/report/total_stock_summary/total_stock_summary.py b/erpnext/stock/report/total_stock_summary/total_stock_summary.py index 41e2f86f29..ed52393923 100644 --- a/erpnext/stock/report/total_stock_summary/total_stock_summary.py +++ b/erpnext/stock/report/total_stock_summary/total_stock_summary.py @@ -30,7 +30,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 += " 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" diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html index e857ce1be0..fe53f34dba 100644 --- a/erpnext/templates/includes/cart/cart_address.html +++ b/erpnext/templates/includes/cart/cart_address.html @@ -104,7 +104,7 @@ frappe.ready(() => { { label: __('Country'), fieldname: 'country', - fieldtype: 'Data', + fieldtype: 'Link', reqd: 1 }, ],