diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index f117ef009e6..93489231cf0 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -173,7 +173,7 @@ class AccountsController(TransactionBase): self.validate_qty_is_not_zero() if ( - self.doctype in ["Sales Invoice", "Purchase Invoice"] + self.doctype in ["Sales Invoice", "Purchase Invoice", "POS Invoice"] and self.get("is_return") and self.get("update_stock") ): diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 24767d97b86..ebbd381eb27 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -258,7 +258,7 @@ def get_already_returned_items(doc): field = ( frappe.scrub(doc.doctype) + "_item" - if doc.doctype in ["Purchase Invoice", "Purchase Receipt", "Sales Invoice"] + if doc.doctype in ["Purchase Invoice", "Purchase Receipt", "Sales Invoice", "POS Invoice"] else "dn_detail" ) data = frappe.db.sql( @@ -770,6 +770,7 @@ def get_return_against_item_fields(voucher_type): "Delivery Note": "dn_detail", "Sales Invoice": "sales_invoice_item", "Subcontracting Receipt": "subcontracting_receipt_item", + "POS Invoice": "sales_invoice_item", } return return_against_item_fields[voucher_type] @@ -1162,3 +1163,29 @@ def get_available_serial_nos(serial_nos, warehouse): def get_payment_data(invoice): payment = frappe.db.get_all("Sales Invoice Payment", {"parent": invoice}, ["mode_of_payment", "amount"]) return payment + + +@frappe.whitelist() +def get_pos_invoice_item_returned_qty(pos_invoice, customer, item_row_name): + is_return, docstatus = frappe.db.get_value("POS Invoice", pos_invoice, ["is_return", "docstatus"]) + if not is_return and docstatus == 1: + return get_returned_qty_map_for_row(pos_invoice, customer, item_row_name, "POS Invoice") + + +@frappe.whitelist() +def is_pos_invoice_returnable(pos_invoice): + is_return, docstatus, customer = frappe.db.get_value( + "POS Invoice", pos_invoice, ["is_return", "docstatus", "customer"] + ) + if is_return or docstatus == 0: + return False + + invoice_item_qty = frappe.db.get_all("POS Invoice Item", {"parent": pos_invoice}, ["name", "qty"]) + + already_full_returned = 0 + for d in invoice_item_qty: + returned_qty = get_returned_qty_map_for_row(pos_invoice, customer, d.name, "POS Invoice") + if returned_qty.qty == d.qty: + already_full_returned += 1 + + return len(invoice_item_qty) != already_full_returned diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss index 1ed34a25730..b0990295105 100644 --- a/erpnext/public/scss/point-of-sale.scss +++ b/erpnext/public/scss/point-of-sale.scss @@ -1087,34 +1087,49 @@ > .item-row-wrapper { display: flex; - align-items: center; + gap: 2px; + flex-direction: column; padding: var(--padding-sm) var(--padding-md); + border: 1px solid lightgray; + border-radius: 10px; + background: var(--bg-light-gray); - > .item-name { - @extend .nowrap; - font-weight: 500; - margin-right: var(--margin-md); - } - - > .item-qty { - font-weight: 500; - margin-left: auto; - } - - > .item-rate-disc { + > .item-row-data { display: flex; - text-align: right; - margin-left: var(--margin-md); - justify-content: flex-end; + align-items: center; - > .item-disc { - color: var(--dark-green-500); - } - - > .item-rate { + > .item-name { + @extend .nowrap; font-weight: 500; - margin-left: var(--margin-md); + margin-right: var(--margin-md); } + + > .item-qty { + font-weight: 500; + margin-left: auto; + font-size: small; + } + + > .item-rate-disc { + display: flex; + text-align: right; + margin-left: var(--margin-md); + justify-content: flex-end; + font-size: small; + + > .item-disc { + color: var(--dark-green-500); + } + + > .item-rate { + font-weight: 500; + margin-left: var(--margin-md); + } + } + } + + > .item-row-refund { + font-size: x-small; } } @@ -1127,6 +1142,12 @@ } } + > .order-summary-container { + display: flex; + background: white; + gap: 8px; + } + > .summary-btns { display: flex; justify-content: space-between; diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 3c1a72d680f..644e4faa156 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -459,6 +459,8 @@ erpnext.PointOfSale.Controller = class { () => this.make_return_invoice(doc), () => this.cart.load_invoice(), () => this.item_selector.toggle_component(true), + () => this.item_selector.resize_selector(false), + () => this.item_details.toggle_component(false), ]); }); }, @@ -469,6 +471,8 @@ erpnext.PointOfSale.Controller = class { () => this.frm.call("reset_mode_of_payments"), () => this.cart.load_invoice(), () => this.item_selector.toggle_component(true), + () => this.item_selector.resize_selector(false), + () => this.item_details.toggle_component(false), ]); }, delete_order: (name) => { diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js index d4b5562c218..0aa464f7c6b 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js @@ -24,7 +24,7 @@ erpnext.PointOfSale.PastOrderSummary = class {