mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-01 19:29:10 +00:00
fix: pos screen ui ux (#47680)
* fix: pos addl info dialog submit form on save * feat: new invoice and recent order button on page action * fix: item cart highlighted item scrolling * fix: using icon instead of text in fullscreen button * fix: search field clear button alignment * fix: hide item selector on item details display * fix: using add_action_icon * fix: action of 'New Invoice' for unsaved changes * fix: highlight numpad btns on hover * fix: pos recent orders filter and list items * chore: added icons for pos icon buttons * fix: recent order toggle after invoice submission * fix: capitalized text in select options
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
"allow_rate_change",
|
"allow_rate_change",
|
||||||
"allow_discount_change",
|
"allow_discount_change",
|
||||||
"set_grand_total_to_default_mop",
|
"set_grand_total_to_default_mop",
|
||||||
|
"action_on_new_invoice",
|
||||||
"section_break_23",
|
"section_break_23",
|
||||||
"item_groups",
|
"item_groups",
|
||||||
"column_break_25",
|
"column_break_25",
|
||||||
@@ -415,6 +416,13 @@
|
|||||||
"fieldname": "set_grand_total_to_default_mop",
|
"fieldname": "set_grand_total_to_default_mop",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Set Grand Total to Default Payment Method"
|
"label": "Set Grand Total to Default Payment Method"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Always Ask",
|
||||||
|
"fieldname": "action_on_new_invoice",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Action on New Invoice",
|
||||||
|
"options": "Always Ask\nSave Changes and Load New Invoice\nDiscard Changes and Load New Invoice"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"grid_page_length": 50,
|
"grid_page_length": 50,
|
||||||
@@ -443,7 +451,7 @@
|
|||||||
"link_fieldname": "pos_profile"
|
"link_fieldname": "pos_profile"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2025-05-09 11:23:28.632136",
|
"modified": "2025-05-23 12:12:32.247652",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Profile",
|
"name": "POS Profile",
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ class POSProfile(Document):
|
|||||||
from erpnext.accounts.doctype.pos_profile_user.pos_profile_user import POSProfileUser
|
from erpnext.accounts.doctype.pos_profile_user.pos_profile_user import POSProfileUser
|
||||||
|
|
||||||
account_for_change_amount: DF.Link | None
|
account_for_change_amount: DF.Link | None
|
||||||
|
action_on_new_invoice: DF.Literal[
|
||||||
|
"Always Ask", "Save Changes and Load New Invoice", "Discard Changes and Load New Invoice"
|
||||||
|
]
|
||||||
allow_discount_change: DF.Check
|
allow_discount_change: DF.Check
|
||||||
allow_rate_change: DF.Check
|
allow_rate_change: DF.Check
|
||||||
applicable_for_users: DF.Table[POSProfileUser]
|
applicable_for_users: DF.Table[POSProfileUser]
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ web_include_js = "erpnext-web.bundle.js"
|
|||||||
web_include_css = "erpnext-web.bundle.css"
|
web_include_css = "erpnext-web.bundle.css"
|
||||||
email_css = "email_erpnext.bundle.css"
|
email_css = "email_erpnext.bundle.css"
|
||||||
|
|
||||||
|
app_include_icons = [
|
||||||
|
"/assets/erpnext/icons/pos-icons.svg",
|
||||||
|
]
|
||||||
|
|
||||||
|
web_include_icons = [
|
||||||
|
"/assets/erpnext/icons/pos-icons.svg",
|
||||||
|
]
|
||||||
|
|
||||||
doctype_js = {
|
doctype_js = {
|
||||||
"Address": "public/js/address.js",
|
"Address": "public/js/address.js",
|
||||||
"Communication": "public/js/communication.js",
|
"Communication": "public/js/communication.js",
|
||||||
|
|||||||
15
erpnext/public/icons/pos-icons.svg
Normal file
15
erpnext/public/icons/pos-icons.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!-- Icons for POS Icon Buttons. Taken from frappe/public/icons/lucide.svg -->
|
||||||
|
|
||||||
|
<svg id="frappe-symbols" aria-hidden="true" style="display: none;" class="icon" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-fullscreen">
|
||||||
|
<path d="M3 7V5a2 2 0 0 1 2-2h2" /> <path d="M17 3h2a2 2 0 0 1 2 2v2" /> <path d="M21 17v2a2 2 0 0 1-2 2h-2" /> <path d="M7 21H5a2 2 0 0 1-2-2v-2" /> <rect width="10" height="8" x="7" y="8" rx="1" />
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-maximize">
|
||||||
|
<path d="M8 3H5a2 2 0 0 0-2 2v3" /> <path d="M21 8V5a2 2 0 0 0-2-2h-3" /> <path d="M3 16v3a2 2 0 0 0 2 2h3" /> <path d="M16 21h3a2 2 0 0 0 2-2v-3" />
|
||||||
|
</symbol>
|
||||||
|
|
||||||
|
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-minimize">
|
||||||
|
<path d="M8 3v3a2 2 0 0 1-2 2H3" /> <path d="M21 8h-3a2 2 0 0 1-2-2V3" /> <path d="M3 16h3a2 2 0 0 1 2 2v3" /> <path d="M16 21v-3a2 2 0 0 1 2-2h3" />
|
||||||
|
</symbol>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1011 B |
@@ -579,7 +579,11 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: var(--padding-md);
|
padding: var(--padding-md);
|
||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-base);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--control-bg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .col-span-2 {
|
> .col-span-2 {
|
||||||
@@ -615,26 +619,30 @@
|
|||||||
background-color: var(--control-bg);
|
background-color: var(--control-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .invoice-name-date {
|
&.invoice-selected {
|
||||||
|
background-color: var(--control-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .invoice-name-customer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
|
|
||||||
> .invoice-name {
|
> .invoice-customer {
|
||||||
@extend .nowrap;
|
@extend .nowrap;
|
||||||
font-size: var(--text-md);
|
font-size: var(--text-md);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .invoice-date {
|
> .invoice-name {
|
||||||
@extend .nowrap;
|
@extend .nowrap;
|
||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .invoice-total-status {
|
> .invoice-total-date {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -648,17 +656,19 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .invoice-status {
|
> .invoice-date {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: var(--gray-500);
|
||||||
justify-content: right;
|
justify-content: right;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .item-details-container {
|
> .item-details-container {
|
||||||
@extend .pos-card;
|
@extend .pos-card;
|
||||||
grid-column: span 4 / span 4;
|
grid-column: span 6 / span 6;
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: var(--padding-lg);
|
padding: var(--padding-lg);
|
||||||
@@ -915,6 +925,10 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: var(--padding-md);
|
padding: var(--padding-md);
|
||||||
box-shadow: var(--shadow-base);
|
box-shadow: var(--shadow-base);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--control-bg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -978,18 +992,23 @@
|
|||||||
background-color: var(--fg-color);
|
background-color: var(--fg-color);
|
||||||
padding: var(--padding-lg);
|
padding: var(--padding-lg);
|
||||||
|
|
||||||
> .search-field {
|
> .status-search-fields {
|
||||||
width: 100%;
|
display: grid;
|
||||||
display: flex;
|
grid-template-columns: 30% auto;
|
||||||
align-items: center;
|
column-gap: 10px;
|
||||||
margin-top: var(--margin-md);
|
margin-top: var(--margin-md);
|
||||||
margin-bottom: var(--margin-xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .status-field {
|
> .status-field {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .search-field {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
this.prepare_dom();
|
this.prepare_dom();
|
||||||
this.prepare_components();
|
this.prepare_components();
|
||||||
this.prepare_menu();
|
this.prepare_menu();
|
||||||
this.prepare_fullscreen_btn();
|
this.prepare_btns();
|
||||||
this.make_new_invoice();
|
this.make_new_invoice();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,52 +234,42 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
|
|
||||||
prepare_menu() {
|
prepare_menu() {
|
||||||
this.page.clear_menu();
|
this.page.clear_menu();
|
||||||
|
|
||||||
this.page.add_menu_item(__("Open Form View"), this.open_form_view.bind(this), false, "Ctrl+F");
|
this.page.add_menu_item(__("Open Form View"), this.open_form_view.bind(this), false, "Ctrl+F");
|
||||||
|
|
||||||
this.page.add_menu_item(
|
|
||||||
__("Toggle Recent Orders"),
|
|
||||||
this.toggle_recent_order.bind(this),
|
|
||||||
false,
|
|
||||||
"Ctrl+O"
|
|
||||||
);
|
|
||||||
|
|
||||||
this.page.add_menu_item(__("Save as Draft"), this.save_draft_invoice.bind(this), false, "Ctrl+S");
|
|
||||||
|
|
||||||
this.page.add_menu_item(__("Close the POS"), this.close_pos.bind(this), false, "Shift+Ctrl+C");
|
this.page.add_menu_item(__("Close the POS"), this.close_pos.bind(this), false, "Shift+Ctrl+C");
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_fullscreen_btn() {
|
prepare_btns() {
|
||||||
this.page.page_actions.find(".custom-actions").empty();
|
this.page.clear_custom_actions();
|
||||||
|
this.page.clear_icons();
|
||||||
this.page.add_button(__("Full Screen"), null, { btn_class: "btn-default fullscreen-btn" });
|
this.page.set_primary_action(__("New Invoice"), this.new_invoice_event.bind(this));
|
||||||
|
this.page.set_secondary_action(__("Recent Orders"), this.toggle_recent_order.bind(this));
|
||||||
this.bind_fullscreen_events();
|
this.page.add_action_icon(
|
||||||
|
"fullscreen",
|
||||||
|
this.bind_fullscreen_events.bind(this),
|
||||||
|
"btn-fullscreen",
|
||||||
|
"Fullscreen"
|
||||||
|
);
|
||||||
|
this.page.add_action_icon(
|
||||||
|
"minimize",
|
||||||
|
this.bind_fullscreen_events.bind(this),
|
||||||
|
"btn-minimize hide",
|
||||||
|
"Minimize"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bind_fullscreen_events() {
|
bind_fullscreen_events() {
|
||||||
this.$fullscreen_btn = this.page.page_actions.find(".fullscreen-btn");
|
if (!document.fullscreenElement) {
|
||||||
|
document.documentElement.requestFullscreen();
|
||||||
this.$fullscreen_btn.on("click", function () {
|
this.toggle_fullscreen_btn(".btn-minimize", ".btn-fullscreen");
|
||||||
if (!document.fullscreenElement) {
|
} else if (document.exitFullscreen) {
|
||||||
document.documentElement.requestFullscreen();
|
document.exitFullscreen();
|
||||||
} else if (document.exitFullscreen) {
|
this.toggle_fullscreen_btn(".btn-fullscreen", ".btn-minimize");
|
||||||
document.exitFullscreen();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("fullscreenchange", this.handle_fullscreen_change_event.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_fullscreen_change_event() {
|
toggle_fullscreen_btn(show, hide) {
|
||||||
let enable_fullscreen_label = __("Full Screen");
|
this.page.page_actions.find(hide).addClass("hide");
|
||||||
let exit_fullscreen_label = __("Exit Full Screen");
|
this.page.page_actions.find(show).removeClass("hide");
|
||||||
|
|
||||||
if (document.fullscreenElement) {
|
|
||||||
this.$fullscreen_btn[0].innerText = exit_fullscreen_label;
|
|
||||||
} else {
|
|
||||||
this.$fullscreen_btn[0].innerText = enable_fullscreen_label;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open_form_view() {
|
open_form_view() {
|
||||||
@@ -289,36 +279,48 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
|
|
||||||
toggle_recent_order() {
|
toggle_recent_order() {
|
||||||
const show = this.recent_order_list.$component.is(":hidden");
|
const show = this.recent_order_list.$component.is(":hidden");
|
||||||
|
this.page.btn_secondary.get(0).innerText = show ? __("Hide Recent Orders") : __("Recent Orders");
|
||||||
this.toggle_recent_order_list(show);
|
this.toggle_recent_order_list(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
save_draft_invoice() {
|
new_invoice_event() {
|
||||||
|
const me = this;
|
||||||
if (!this.$components_wrapper.is(":visible")) return;
|
if (!this.$components_wrapper.is(":visible")) return;
|
||||||
|
|
||||||
if (this.frm.doc.items.length == 0) {
|
if (this.frm.doc.items.length !== 0 && (this.frm.is_new() || this.frm.is_dirty())) {
|
||||||
frappe.show_alert({
|
if (this.settings.action_on_new_invoice === "Always Ask") {
|
||||||
message: __("You must add atleast one item to save it as draft."),
|
frappe.confirm(
|
||||||
indicator: "red",
|
__("You have unsaved changes. Do you want to save the invoice?"),
|
||||||
});
|
() => {
|
||||||
frappe.utils.play_sound("error");
|
me.frm.save().then(me.load_new_invoice_on_pos.bind(me));
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
me.load_new_invoice_on_pos();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else if (this.settings.action_on_new_invoice === "Save Changes and Load New Invoice") {
|
||||||
|
this.frm.save().then(me.load_new_invoice_on_pos.bind(me));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.load_new_invoice_on_pos();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.frm
|
if (this.payment.$component.is(":visible")) {
|
||||||
.save(undefined, undefined, undefined, () => {
|
this.load_new_invoice_on_pos();
|
||||||
frappe.show_alert({
|
}
|
||||||
message: __("There was an error saving the document."),
|
}
|
||||||
indicator: "red",
|
|
||||||
});
|
load_new_invoice_on_pos() {
|
||||||
frappe.utils.play_sound("error");
|
frappe.run_serially([
|
||||||
})
|
() => frappe.dom.freeze(),
|
||||||
.then(() => {
|
() => this.make_new_invoice(),
|
||||||
frappe.run_serially([
|
() => this.toggle_recent_order_list(false),
|
||||||
() => frappe.dom.freeze(),
|
() => this.toggle_components(true),
|
||||||
() => this.make_new_invoice(),
|
() => frappe.dom.unfreeze(),
|
||||||
() => frappe.dom.unfreeze(),
|
]);
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close_pos() {
|
close_pos() {
|
||||||
@@ -384,7 +386,7 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
get_frm: () => this.frm,
|
get_frm: () => this.frm,
|
||||||
|
|
||||||
toggle_item_selector: (minimize) => {
|
toggle_item_selector: (minimize) => {
|
||||||
this.item_selector.resize_selector(minimize);
|
this.item_selector.toggle_component(!minimize);
|
||||||
this.cart.toggle_numpad(minimize);
|
this.cart.toggle_numpad(minimize);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -468,8 +470,7 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
submit_invoice: () => {
|
submit_invoice: () => {
|
||||||
this.frm.savesubmit().then((r) => {
|
this.frm.savesubmit().then((r) => {
|
||||||
this.toggle_components(false);
|
this.toggle_components(false);
|
||||||
this.order_summary.toggle_component(true);
|
this.toggle_submitted_invoice_summary(true);
|
||||||
this.order_summary.load_summary_of(this.frm.doc, true);
|
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
indicator: "green",
|
indicator: "green",
|
||||||
message: __("POS invoice {0} created successfully", [r.doc.name]),
|
message: __("POS invoice {0} created successfully", [r.doc.name]),
|
||||||
@@ -518,7 +519,7 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
edit_order: (doctype, name) => {
|
edit_order: (doctype, name) => {
|
||||||
this.recent_order_list.toggle_component(false);
|
this.toggle_recent_order();
|
||||||
frappe.run_serially([
|
frappe.run_serially([
|
||||||
() => this.make_invoice_frm(doctype),
|
() => this.make_invoice_frm(doctype),
|
||||||
() => this.sync_draft_invoice_to_frm(doctype, name),
|
() => this.sync_draft_invoice_to_frm(doctype, name),
|
||||||
@@ -550,19 +551,29 @@ erpnext.PointOfSale.Controller = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggle_recent_order_list(show) {
|
toggle_recent_order_list(show) {
|
||||||
this.toggle_components(!show);
|
this.frm.doc.docstatus === 1
|
||||||
|
? this.toggle_submitted_invoice_summary(!show)
|
||||||
|
: this.toggle_components(!show);
|
||||||
|
|
||||||
this.recent_order_list.toggle_component(show);
|
this.recent_order_list.toggle_component(show);
|
||||||
this.order_summary.toggle_component(show);
|
if (this.frm.doc.docstatus === 0) this.order_summary.toggle_component(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle_components(show) {
|
toggle_components(show) {
|
||||||
this.cart.toggle_component(show);
|
this.cart.toggle_component(show);
|
||||||
|
this.cart.toggle_numpad(!show);
|
||||||
|
this.cart.toggle_checkout_btn(show);
|
||||||
this.item_selector.toggle_component(show);
|
this.item_selector.toggle_component(show);
|
||||||
|
|
||||||
// do not show item details or payment if recent order is toggled off
|
// do not show item details or payment if recent order is toggled off
|
||||||
!show ? this.item_details.toggle_component(false) || this.payment.toggle_component(false) : "";
|
!show ? this.item_details.toggle_component(false) || this.payment.toggle_component(false) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggle_submitted_invoice_summary(show) {
|
||||||
|
this.order_summary.toggle_component(show);
|
||||||
|
this.order_summary.load_summary_of(this.frm.doc, true);
|
||||||
|
}
|
||||||
|
|
||||||
make_new_invoice() {
|
make_new_invoice() {
|
||||||
return frappe.run_serially([
|
return frappe.run_serially([
|
||||||
() => frappe.dom.freeze(),
|
() => frappe.dom.freeze(),
|
||||||
|
|||||||
@@ -171,8 +171,11 @@ erpnext.PointOfSale.ItemCart = class {
|
|||||||
|
|
||||||
me.toggle_item_highlight(this);
|
me.toggle_item_highlight(this);
|
||||||
|
|
||||||
const scrollTop = $cart_item.offset().top - me.$cart_items_wrapper.offset().top;
|
const numpad_section_hidden = !me.$numpad_section.is(":visible");
|
||||||
me.$cart_items_wrapper.animate({ scrollTop });
|
if (numpad_section_hidden) {
|
||||||
|
const scrollTop = $cart_item.offset().top - me.$cart_items_wrapper.offset().top;
|
||||||
|
me.$cart_items_wrapper.animate({ scrollTop });
|
||||||
|
}
|
||||||
|
|
||||||
const payment_section_hidden = !me.$totals_section.find(".edit-cart-btn").is(":visible");
|
const payment_section_hidden = !me.$totals_section.find(".edit-cart-btn").is(":visible");
|
||||||
if (!payment_section_hidden) {
|
if (!payment_section_hidden) {
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ erpnext.PointOfSale.ItemSelector = class {
|
|||||||
|
|
||||||
attach_clear_btn() {
|
attach_clear_btn() {
|
||||||
this.search_field.$wrapper.find(".control-input").append(
|
this.search_field.$wrapper.find(".control-input").append(
|
||||||
`<span class="link-btn" style="top: 2px;">
|
`<span class="link-btn">
|
||||||
<a class="btn-open no-decoration" title="${__("Clear")}">
|
<a class="btn-open no-decoration" title="${__("Clear")}">
|
||||||
${frappe.utils.icon("close", "sm")}
|
${frappe.utils.icon("close", "sm")}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ erpnext.PointOfSale.PastOrderList = class {
|
|||||||
`<section class="past-order-list">
|
`<section class="past-order-list">
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
<div class="label">${__("Recent Orders")}</div>
|
<div class="label">${__("Recent Orders")}</div>
|
||||||
<div class="search-field"></div>
|
<div class="status-search-fields">
|
||||||
<div class="status-field"></div>
|
<div class="status-field"></div>
|
||||||
|
<div class="search-field"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="invoices-container"></div>
|
<div class="invoices-container"></div>
|
||||||
</section>`
|
</section>`
|
||||||
@@ -38,8 +40,12 @@ erpnext.PointOfSale.PastOrderList = class {
|
|||||||
});
|
});
|
||||||
const me = this;
|
const me = this;
|
||||||
this.$invoices_container.on("click", ".invoice-wrapper", function () {
|
this.$invoices_container.on("click", ".invoice-wrapper", function () {
|
||||||
const invoice_doctype = $(this).attr("data-invoice-doctype");
|
const invoice_clicked = $(this);
|
||||||
const invoice_name = unescape($(this).attr("data-invoice-name"));
|
const invoice_doctype = invoice_clicked.attr("data-invoice-doctype");
|
||||||
|
const invoice_name = unescape(invoice_clicked.attr("data-invoice-name"));
|
||||||
|
|
||||||
|
$(".invoice-wrapper").removeClass("invoice-selected");
|
||||||
|
invoice_clicked.addClass("invoice-selected");
|
||||||
|
|
||||||
me.events.open_invoice_data(invoice_doctype, invoice_name);
|
me.events.open_invoice_data(invoice_doctype, invoice_name);
|
||||||
});
|
});
|
||||||
@@ -103,16 +109,16 @@ erpnext.PointOfSale.PastOrderList = class {
|
|||||||
return `<div class="invoice-wrapper" data-invoice-doctype="${
|
return `<div class="invoice-wrapper" data-invoice-doctype="${
|
||||||
invoice.doctype
|
invoice.doctype
|
||||||
}" data-invoice-name="${escape(invoice.name)}">
|
}" data-invoice-name="${escape(invoice.name)}">
|
||||||
<div class="invoice-name-date">
|
<div class="invoice-name-customer">
|
||||||
<div class="invoice-name">${invoice.name}</div>
|
<div class="invoice-customer">
|
||||||
<div class="invoice-date">
|
|
||||||
<svg class="mr-2" width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="mr-2" width="12" height="12" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
|
||||||
</svg>
|
</svg>
|
||||||
${frappe.ellipsis(invoice.customer, 20)}
|
${frappe.ellipsis(invoice.customer, 20)}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invoice-name">${invoice.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="invoice-total-status">
|
<div class="invoice-total-date">
|
||||||
<div class="invoice-total">${format_currency(invoice.grand_total, invoice.currency) || 0}</div>
|
<div class="invoice-total">${format_currency(invoice.grand_total, invoice.currency) || 0}</div>
|
||||||
<div class="invoice-date">${posting_datetime}</div>
|
<div class="invoice-date">${posting_datetime}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -459,6 +459,7 @@ erpnext.PointOfSale.PastOrderSummary = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggle_component(show) {
|
toggle_component(show) {
|
||||||
|
this.$component.css("grid-column", "span 6 / span 6");
|
||||||
show ? this.$component.css("display", "flex") : this.$component.css("display", "none");
|
show ? this.$component.css("display", "flex") : this.$component.css("display", "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,15 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
primary_action_label: __("Save"),
|
primary_action_label: __("Save"),
|
||||||
primary_action(values) {
|
primary_action(values) {
|
||||||
me.set_values_to_frm(values);
|
me.set_values_to_frm(values);
|
||||||
|
if (this.complete_order) {
|
||||||
|
me.events.submit_invoice();
|
||||||
|
}
|
||||||
this.hide();
|
this.hide();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
me.addl_dlg.$wrapper.on("hide.bs.modal", function () {
|
||||||
|
me.addl_dlg.complete_order = false;
|
||||||
|
});
|
||||||
me.add_btn_field_click_listener();
|
me.add_btn_field_click_listener();
|
||||||
me.set_value_on_dialog_fields();
|
me.set_value_on_dialog_fields();
|
||||||
me.make_addl_info_dialog_btn_visible();
|
me.make_addl_info_dialog_btn_visible();
|
||||||
@@ -218,10 +224,6 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
const paid_amount = doc.paid_amount;
|
const paid_amount = doc.paid_amount;
|
||||||
const items = doc.items;
|
const items = doc.items;
|
||||||
|
|
||||||
if (!this.validate_reqd_invoice_fields()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!items.length || (paid_amount == 0 && doc.additional_discount_percentage != 100)) {
|
if (!items.length || (paid_amount == 0 && doc.additional_discount_percentage != 100)) {
|
||||||
const message = items.length
|
const message = items.length
|
||||||
? __("You cannot submit the order without payment.")
|
? __("You cannot submit the order without payment.")
|
||||||
@@ -231,6 +233,10 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.validate_reqd_invoice_fields()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.events.submit_invoice();
|
this.events.submit_invoice();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -683,16 +689,12 @@ erpnext.PointOfSale.Payment = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate_reqd_invoice_fields() {
|
validate_reqd_invoice_fields() {
|
||||||
|
if (this.invoice_fields.length === 0) return true;
|
||||||
const doc = this.events.get_frm().doc;
|
const doc = this.events.get_frm().doc;
|
||||||
for (const df of this.addl_dlg.fields) {
|
for (const df of this.addl_dlg.fields) {
|
||||||
if (df.reqd && !doc[df.fieldname]) {
|
if (df.reqd && !doc[df.fieldname]) {
|
||||||
frappe.show_alert({
|
this.addl_dlg.primary_action_label = "Submit";
|
||||||
message: __(
|
this.addl_dlg.complete_order = true;
|
||||||
"Invoice cannot be submitted without filling the mandatory Additional Information fields."
|
|
||||||
),
|
|
||||||
indicator: "red",
|
|
||||||
});
|
|
||||||
frappe.utils.play_sound("error");
|
|
||||||
this.addl_dlg.show();
|
this.addl_dlg.show();
|
||||||
this.addl_dlg.fields_dict[df.fieldname].$input.focus();
|
this.addl_dlg.fields_dict[df.fieldname].$input.focus();
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user