fix: improve pos return (#45671)
* fix: pos return validation for zero qty item * fix: pos return invoice onload ui * feat: added item qty returned in pos ui * refactor: removed console log statement * feat: check return can be made before loading it on pos * fix: pos edit invoice onload ui * fix: returned * refactor: code cleanup
This commit is contained in:
@@ -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")
|
||||
):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -24,7 +24,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
<div class="abs-container">
|
||||
<div class="upper-section"></div>
|
||||
<div class="label">${__("Items")}</div>
|
||||
<div class="items-container summary-container"></div>
|
||||
<div class="items-container summary-container order-summary-container"></div>
|
||||
<div class="label">${__("Totals")}</div>
|
||||
<div class="totals-container summary-container"></div>
|
||||
<div class="label">${__("Payments")}</div>
|
||||
@@ -90,12 +90,18 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
get_item_html(doc, item_data) {
|
||||
async get_item_html(doc, item_data) {
|
||||
const item_refund_data = doc.is_return || doc.docstatus === 0 ? "" : await get_returned_qty();
|
||||
|
||||
return `<div class="item-row-wrapper">
|
||||
<div class="item-row-data">
|
||||
<div class="item-name">${item_data.item_name}</div>
|
||||
<div class="item-qty">${item_data.qty || 0} ${item_data.uom}</div>
|
||||
<div class="item-rate-disc">${get_rate_discount_html()}</div>
|
||||
</div>`;
|
||||
</div>
|
||||
|
||||
${item_refund_data}
|
||||
</div>`;
|
||||
|
||||
function get_rate_discount_html() {
|
||||
if (item_data.rate && item_data.price_list_rate && item_data.rate !== item_data.price_list_rate) {
|
||||
@@ -108,6 +114,25 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
)}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function get_returned_qty() {
|
||||
const r = await frappe.call({
|
||||
method: "erpnext.controllers.sales_and_purchase_return.get_pos_invoice_item_returned_qty",
|
||||
args: {
|
||||
pos_invoice: doc.name,
|
||||
customer: doc.customer,
|
||||
item_row_name: item_data.name,
|
||||
},
|
||||
});
|
||||
|
||||
if (!r.message.qty) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `<div class="item-row-refund">
|
||||
<strong>${r.message.qty}</strong> ${__("Returned")}
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
get_discount_html(doc) {
|
||||
@@ -166,7 +191,16 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
}
|
||||
|
||||
bind_events() {
|
||||
this.$summary_container.on("click", ".return-btn", () => {
|
||||
this.$summary_container.on("click", ".return-btn", async () => {
|
||||
const r = await this.is_pos_invoice_returnable(this.doc.name);
|
||||
if (!r) {
|
||||
frappe.msgprint({
|
||||
title: __("Invalid Return"),
|
||||
indicator: "orange",
|
||||
message: __("All the items have been already returned."),
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.events.process_return(this.doc.name);
|
||||
this.toggle_component(false);
|
||||
this.$component.find(".no-summary-placeholder").css("display", "flex");
|
||||
@@ -370,13 +404,13 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
});
|
||||
}
|
||||
|
||||
attach_items_info(doc) {
|
||||
async attach_items_info(doc) {
|
||||
this.$items_container.html("");
|
||||
doc.items.forEach((item) => {
|
||||
const item_dom = this.get_item_html(doc, item);
|
||||
for (const item of doc.items) {
|
||||
const item_dom = await this.get_item_html(doc, item);
|
||||
this.$items_container.append(item_dom);
|
||||
this.set_dynamic_rate_header_width();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
set_dynamic_rate_header_width() {
|
||||
@@ -438,4 +472,14 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
||||
this.print_receipt();
|
||||
}
|
||||
}
|
||||
|
||||
async is_pos_invoice_returnable(invoice) {
|
||||
const r = await frappe.call({
|
||||
method: "erpnext.controllers.sales_and_purchase_return.is_pos_invoice_returnable",
|
||||
args: {
|
||||
pos_invoice: invoice,
|
||||
},
|
||||
});
|
||||
return r.message;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user