feat: pos item details with new ui
This commit is contained in:
parent
cc208839cf
commit
fc3315a6d7
@ -119,7 +119,6 @@
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: var(--margin-lg);
|
||||
flex: 1 1 0%;
|
||||
padding: var(--padding-lg);
|
||||
padding-top: var(--padding-xs);
|
||||
|
||||
@ -471,6 +470,13 @@
|
||||
background-color: var(--blue-200);
|
||||
color: white;
|
||||
}
|
||||
|
||||
> .edit-cart-btn {
|
||||
@extend .primary-action;
|
||||
display: none;
|
||||
background-color: var(--gray-100);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
> .numpad-section {
|
||||
@ -542,7 +548,7 @@
|
||||
> .invoice-name-date {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
justify-content: flex-end;
|
||||
|
||||
> .invoice-name {
|
||||
@extend .nowrap;
|
||||
@ -580,4 +586,108 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .item-details-container {
|
||||
@extend .pos-card;
|
||||
grid-column: span 4 / span 4;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
padding: var(--padding-lg);
|
||||
padding-top: var(--padding-md);
|
||||
|
||||
> .item-details-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--margin-md);
|
||||
|
||||
> .close-btn {
|
||||
@extend .pointer-no-select;
|
||||
}
|
||||
}
|
||||
|
||||
> .item-display {
|
||||
display: flex;
|
||||
|
||||
> .item-name-desc-price {
|
||||
flex: 1 1 0%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
margin-right: var(--margin-md);
|
||||
|
||||
> .item-name {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
> .item-desc {
|
||||
font-size: var(--text-md);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
> .item-price {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
> .item-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 11rem;
|
||||
height: 11rem;
|
||||
border-radius: var(--border-radius-md);
|
||||
margin-left: var(--margin-md);
|
||||
color: var(--gray-500);
|
||||
|
||||
> img {
|
||||
@extend .image;
|
||||
}
|
||||
|
||||
> .item-abbr {
|
||||
@extend .abbr;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--border-radius-md);
|
||||
font-size: var(--text-3xl);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .discount-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: var(--margin-sm);
|
||||
|
||||
> .item-rate {
|
||||
font-weight: 500;
|
||||
margin-right: var(--margin-sm);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
> .item-discount {
|
||||
padding: 3px var(--padding-sm);
|
||||
border-radius: var(--border-radius-sm);
|
||||
background-color: var(--green-100);
|
||||
color: var(--green-700);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
> .form-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
column-gap: var(--padding-xs);
|
||||
|
||||
> .auto-fetch-btn {
|
||||
@extend .pointer-no-select;
|
||||
margin: auto var(--margin-xs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -95,9 +95,7 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
<div>0.00</div>
|
||||
</div>
|
||||
<div class="checkout-btn">Checkout</div>
|
||||
<div class="edit-cart-btn flex items-center justify-center h-16 pr-8 pl-8 text-center text-grey no-select pointer d-none text-md text-bold">
|
||||
Edit Cart
|
||||
</div>`
|
||||
<div class="edit-cart-btn">Edit Cart</div>`
|
||||
)
|
||||
|
||||
this.$add_discount_elem = this.$component.find(".add-discount");
|
||||
@ -176,7 +174,7 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
});
|
||||
|
||||
this.$component.on('click', '.checkout-btn', function() {
|
||||
if (!$(this).hasClass('bg-primary')) return;
|
||||
if ($(this).attr('style').indexOf('--blue-500') == -1) return;
|
||||
|
||||
me.events.checkout();
|
||||
me.toggle_checkout_btn(false);
|
||||
@ -265,8 +263,9 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
|
||||
toggle_item_highlight(item) {
|
||||
const $cart_item = $(item);
|
||||
const item_is_highlighted = $cart_item.attr("style") == "background-color:var(--gray-50);";
|
||||
|
||||
if (!item) {
|
||||
if (!item || item_is_highlighted) {
|
||||
this.item_is_selected = false;
|
||||
this.$cart_container.find('.cart-item-wrapper').css("background-color", "");
|
||||
} else {
|
||||
@ -522,7 +521,7 @@ erpnext.PointOfSale.ItemCart = class {
|
||||
const $item = this.get_cart_item(item);
|
||||
|
||||
if (remove_item) {
|
||||
$item && $item.remove();
|
||||
$item && $item.next().remove() && $item.remove();
|
||||
} else {
|
||||
const { item_code, batch_no, uom } = item;
|
||||
const search_field = batch_no ? 'batch_no' : 'item_code';
|
||||
|
@ -16,35 +16,36 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
|
||||
prepare_dom() {
|
||||
this.wrapper.append(
|
||||
`<section class="col-span-4 flex shadow rounded item-details bg-white mx-h-70 h-100 d-none"></section>`
|
||||
`<section class="item-details-container"></section>`
|
||||
)
|
||||
|
||||
this.$component = this.wrapper.find('.item-details');
|
||||
this.$component = this.wrapper.find('.item-details-container');
|
||||
}
|
||||
|
||||
init_child_components() {
|
||||
this.$component.html(
|
||||
`<div class="details-container flex flex-col p-8 rounded w-full">
|
||||
<div class="flex justify-between mb-2">
|
||||
<div class="text-grey">ITEM DETAILS</div>
|
||||
<div class="close-btn text-grey hover-underline pointer no-select">Close</div>
|
||||
`<div class="item-details-header">
|
||||
<div class="label">Item Details</div>
|
||||
<div class="close-btn">
|
||||
<svg width="32" height="32" viewBox="0 0 14 14" fill="none">
|
||||
<path d="M4.93764 4.93759L7.00003 6.99998M9.06243 9.06238L7.00003 6.99998M7.00003 6.99998L4.93764 9.06238L9.06243 4.93759" stroke="#8D99A6"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="item-defaults flex">
|
||||
<div class="flex-1 flex flex-col justify-end mr-4 mb-2">
|
||||
<div class="item-name text-xl font-weight-450"></div>
|
||||
<div class="item-description text-md-0 text-grey-200"></div>
|
||||
<div class="item-price text-xl font-bold"></div>
|
||||
</div>
|
||||
<div class="item-image flex items-center justify-center w-46 h-46 bg-light-grey rounded ml-4 text-6xl text-grey-100"></div>
|
||||
</div>
|
||||
<div class="item-display">
|
||||
<div class="item-name-desc-price">
|
||||
<div class="item-name"></div>
|
||||
<div class="item-desc"></div>
|
||||
<div class="item-price"></div>
|
||||
</div>
|
||||
<div class="discount-section flex items-center"></div>
|
||||
<div class="text-grey mt-4 mb-6">STOCK DETAILS</div>
|
||||
<div class="form-container grid grid-cols-2 row-gap-2 col-gap-4 grid-auto-row"></div>
|
||||
</div>`
|
||||
<div class="item-image"></div>
|
||||
</div>
|
||||
<div class="discount-section"></div>
|
||||
<div class="form-container"></div>`
|
||||
)
|
||||
|
||||
this.$item_name = this.$component.find('.item-name');
|
||||
this.$item_description = this.$component.find('.item-description');
|
||||
this.$item_description = this.$component.find('.item-desc');
|
||||
this.$item_price = this.$component.find('.item-price');
|
||||
this.$item_image = this.$component.find('.item-image');
|
||||
this.$form_container = this.$component.find('.form-container');
|
||||
@ -52,7 +53,7 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
}
|
||||
|
||||
toggle_item_details_section(item) {
|
||||
const { item_code, batch_no, uom } = this.current_item;
|
||||
const { item_code, batch_no, uom } = this.current_item;
|
||||
const item_code_is_same = item && item_code === item.item_code;
|
||||
const batch_is_same = item && batch_no == item.batch_no;
|
||||
const uom_is_same = item && uom === item.uom;
|
||||
@ -104,11 +105,11 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
}
|
||||
|
||||
render_dom(item) {
|
||||
let { item_code ,item_name, description, image, price_list_rate } = item;
|
||||
let { item_name, description, image, price_list_rate } = item;
|
||||
|
||||
function get_description_html() {
|
||||
if (description) {
|
||||
description = description.indexOf('...') === -1 && description.length > 75 ? description.substr(0, 73) + '...' : description;
|
||||
description = description.indexOf('...') === -1 && description.length > 140 ? description.substr(0, 139) + '...' : description;
|
||||
return description;
|
||||
}
|
||||
return ``;
|
||||
@ -118,11 +119,9 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
this.$item_description.html(get_description_html());
|
||||
this.$item_price.html(format_currency(price_list_rate, this.currency));
|
||||
if (image) {
|
||||
this.$item_image.html(
|
||||
`<img class="h-full" src="${image}" alt="${image}" style="object-fit: cover;">`
|
||||
);
|
||||
this.$item_image.html(`<img src="${image}" alt="${image}">`);
|
||||
} else {
|
||||
this.$item_image.html(frappe.get_abbr(item_code));
|
||||
this.$item_image.html(`<div class="item-abbr">${frappe.get_abbr(item_name)}</div>`);
|
||||
}
|
||||
|
||||
}
|
||||
@ -130,12 +129,8 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
render_discount_dom(item) {
|
||||
if (item.discount_percentage) {
|
||||
this.$dicount_section.html(
|
||||
`<div class="text-grey line-through mr-4 text-md mb-2">
|
||||
${format_currency(item.price_list_rate, this.currency)}
|
||||
</div>
|
||||
<div class="p-1 pr-3 pl-3 rounded w-fit text-bold bg-green-200 mb-2">
|
||||
${item.discount_percentage}% off
|
||||
</div>`
|
||||
`<div class="item-rate">${format_currency(item.price_list_rate, this.currency)}</div>
|
||||
<div class="item-discount">${item.discount_percentage}% off</div>`
|
||||
)
|
||||
this.$item_price.html(format_currency(item.rate, this.currency));
|
||||
} else {
|
||||
@ -149,9 +144,7 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
|
||||
fields_to_display.forEach((fieldname, idx) => {
|
||||
this.$form_container.append(
|
||||
`<div class="">
|
||||
<div class="item_detail_field ${fieldname}-control" data-fieldname="${fieldname}"></div>
|
||||
</div>`
|
||||
`<div class="${fieldname}-control" data-fieldname="${fieldname}"></div>`
|
||||
)
|
||||
|
||||
const field_meta = this.item_meta.fields.find(df => df.fieldname === fieldname);
|
||||
@ -185,22 +178,15 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
|
||||
make_auto_serial_selection_btn(item) {
|
||||
if (item.has_serial_no) {
|
||||
this.$form_container.append(
|
||||
`<div class="grid-filler no-select"></div>`
|
||||
)
|
||||
if (!item.has_batch_no) {
|
||||
this.$form_container.append(
|
||||
`<div class="grid-filler no-select"></div>`
|
||||
)
|
||||
}
|
||||
this.$form_container.append(
|
||||
`<div class="auto-fetch-btn bg-grey-100 border border-grey text-bold rounded pt-3 pb-3 pl-6 pr-8 text-grey pointer no-select mt-2"
|
||||
style="height: 3.3rem">
|
||||
Auto Fetch Serial Numbers
|
||||
</div>`
|
||||
`<div class="btn btn-sm btn-secondary auto-fetch-btn">Auto Fetch Serial Numbers</div>`
|
||||
)
|
||||
this.$form_container.find('.serial_no-control').find('textarea').css('height', '9rem');
|
||||
this.$form_container.find('.serial_no-control').parent().addClass('row-span-2');
|
||||
this.$form_container.find('.serial_no-control').find('textarea').css('height', '6rem');
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,8 +280,13 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
}
|
||||
|
||||
frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
|
||||
const field_control = me[`${fieldname}_control`];
|
||||
if (field_control) {
|
||||
const field_control = this[`${fieldname}_control`];
|
||||
const { item_code, batch_no, uom } = this.current_item;
|
||||
const item_code_is_same = item_code === item_row.item_code;
|
||||
const batch_is_same = batch_no == item_row.batch_no;
|
||||
const uom_is_same = uom === item_row.uom;
|
||||
|
||||
if (field_control && item_code_is_same && batch_is_same && uom_is_same) {
|
||||
field_control.set_value(value);
|
||||
cur_pos.update_cart_html(item_row);
|
||||
}
|
||||
@ -409,6 +400,6 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
}
|
||||
|
||||
toggle_component(show) {
|
||||
show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
|
||||
show ? this.$component.css('display', 'flex') : this.$component.css('display', 'none');
|
||||
}
|
||||
}
|
@ -248,20 +248,16 @@ erpnext.PointOfSale.ItemSelector = class {
|
||||
|
||||
resize_selector(minimize) {
|
||||
minimize ?
|
||||
this.$component.find('.search-field').removeClass('mr-8') :
|
||||
this.$component.find('.search-field').addClass('mr-8');
|
||||
|
||||
minimize ?
|
||||
this.$component.find('.filter-section').addClass('flex-col') :
|
||||
this.$component.find('.filter-section').removeClass('flex-col');
|
||||
this.$component.find('.filter-section').css('grid-template-columns', 'repeat(1, minmax(0, 1fr))') :
|
||||
this.$component.find('.filter-section').css('grid-template-columns', 'repeat(12, minmax(0, 1fr))');
|
||||
|
||||
minimize ?
|
||||
this.$component.removeClass('col-span-6').addClass('col-span-2') :
|
||||
this.$component.removeClass('col-span-2').addClass('col-span-6')
|
||||
this.$component.css('grid-column', 'span 2 / span 2') :
|
||||
this.$component.css('grid-column', 'span 6 / span 6')
|
||||
|
||||
minimize ?
|
||||
this.$items_container.removeClass('grid-cols-4').addClass('grid-cols-1') :
|
||||
this.$items_container.removeClass('grid-cols-1').addClass('grid-cols-4')
|
||||
this.$items_container.css('grid-template-columns', 'repeat(1, minmax(0, 1fr))') :
|
||||
this.$items_container.css('grid-template-columns', 'repeat(4, minmax(0, 1fr))')
|
||||
}
|
||||
|
||||
toggle_component(show) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user