19.0 vanilla
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 1.7 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70" viewBox="0 0 70 70"><defs><path id="a" d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z"/><linearGradient id="c" x1="100%" x2="0%" y1="0%" y2="98.616%"><stop offset="0%" stop-color="#797C79"/><stop offset="100%" stop-color="#545554"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path fill="#FFF" fill-opacity=".383" d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z"/><path fill="#393939" d="M32.25 69H4c-2 0-4-1-4-4V39.181L19 20h32v6.208l1.992 12.632L51 41.123V50L32.25 69z" opacity=".324"/><path fill="#000" fill-opacity=".383" d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z"/><path fill="#000" fill-opacity=".3" d="M51 22H19v3.75h32V22zm2 18.75V37l-2-9.375H19L17 37v3.75h2V52h20V40.75h8V52h4V40.75h2zm-18 7.5H23v-7.5h12v7.5z"/><path fill="#FFF" d="M51 20H19v3.75h32V20zm2 18.75V35l-2-9.375H19L17 35v3.75h2V50h20V38.75h8V50h4V38.75h2zm-18 7.5H23v-7.5h12v7.5z"/></g></g></svg>
|
||||
<svg width="50" height="50" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 8 6 36h6.019a6.5 6.5 0 0 0 12.962 0H25a6 6 0 0 0 12 0h.019a6.5 6.5 0 0 0 12.962 0H50v-1l-.045-.273a6.231 6.231 0 0 0-.058-.386l-.023-.118-.02-.1-3.797-22.78A4 4 0 0 0 42.112 8H9.5Z" fill="#985184"/><path d="m14 8-2 28a6 6 0 0 1-12 0v-1l3.494-23.586A4 4 0 0 1 7.451 8H14Zm21 0 2 28a6 6 0 0 1-12 0V8h10Z" fill="#FBB945"/><path d="M12 36a6 6 0 1 1-12 0h12Zm25 0a6 6 0 0 1-12 0h12Z" fill="#F78613"/><path d="M12.02 36a6.5 6.5 0 0 0 12.961 0H12.02Zm25 0a6.5 6.5 0 0 0 12.961 0H37.02Z" fill="#712258"/></svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 600 B |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 587 B |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 792 B |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 976 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 942 B |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 93 KiB |
28
odoo-bringout-oca-ocb-point_of_sale/point_of_sale/static/src/@types/services.d.ts
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
declare module "services" {
|
||||
import { CustomerDisplayDataService } from "@point_of_sale/customer_display/customer_display_data_service";
|
||||
import { alertService } from "@point_of_sale/app/services/alert_service";
|
||||
import { barcodeReaderService } from "@point_of_sale/app/services/barcode_reader_service";
|
||||
import { contextualUtilsService } from "@point_of_sale/app/services/contextual_utils_service";
|
||||
import { hardwareProxyService } from "@point_of_sale/app/services/hardware_proxy_service";
|
||||
import { numberBufferService } from "@point_of_sale/app/services/number_buffer_service";
|
||||
import { PosDataService } from "@point_of_sale/app/services/data_service";
|
||||
import { posService } from "@point_of_sale/app/services/pos_store";
|
||||
import { posPrinterService } from "@point_of_sale/app/services/pos_printer_service";
|
||||
import { renderService } from "@point_of_sale/app/services/render_service";
|
||||
import { reportService } from "@point_of_sale/app/services/report_service";
|
||||
|
||||
export interface Services {
|
||||
alert: typeof alertService;
|
||||
barcode_reader: typeof barcodeReaderService;
|
||||
contextual_utils_service: typeof contextualUtilsService;
|
||||
customer_display_data: typeof CustomerDisplayDataService;
|
||||
hardware_proxy: typeof hardwareProxyService;
|
||||
number_buffer: typeof numberBufferService;
|
||||
pos: typeof posService;
|
||||
pos_data: typeof PosDataService;
|
||||
printer: typeof posPrinterService;
|
||||
renderer: typeof renderService;
|
||||
report: typeof reportService;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { Component, useState, useRef, useEffect, onMounted } from "@odoo/owl";
|
||||
|
||||
export class AccordionItem extends Component {
|
||||
static template = "pos_hr.AccordionItem";
|
||||
|
||||
static props = {
|
||||
disabled: { type: Boolean, optional: true },
|
||||
slots: Object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
setup() {
|
||||
this.content = useRef("content_container");
|
||||
this.state = useState({
|
||||
open: false,
|
||||
});
|
||||
onMounted(() => {
|
||||
this.contentHeight = this.calculateFullHeight();
|
||||
});
|
||||
useEffect(
|
||||
() => {
|
||||
this.contentHeight = this.calculateFullHeight();
|
||||
},
|
||||
() => [this.props.slots.content]
|
||||
);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
}
|
||||
this.state.open = !this.state.open;
|
||||
}
|
||||
|
||||
calculateFullHeight() {
|
||||
const children = Array.from(this.content.el.getElementsByClassName("accordion-content"));
|
||||
const fullHeight = children.reduce(
|
||||
(accumulator, child) => accumulator + Math.min(this.getHiddenHeight(child), 100),
|
||||
0
|
||||
);
|
||||
return fullHeight;
|
||||
}
|
||||
|
||||
getHiddenHeight(el) {
|
||||
if (!el?.cloneNode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const clone = el.cloneNode(true);
|
||||
|
||||
Object.assign(clone.style, {
|
||||
overflow: "visible",
|
||||
height: "auto",
|
||||
maxHeight: "none",
|
||||
opacity: "0",
|
||||
visibility: "hidden",
|
||||
display: "block",
|
||||
});
|
||||
|
||||
el.after(clone);
|
||||
const height = clone.offsetHeight;
|
||||
clone.remove();
|
||||
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@mixin hide-scrollbar {
|
||||
-ms-overflow-style: none; // IE 10+
|
||||
scrollbar-width: none; // Firefox
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none; // Safari and Chrome
|
||||
}
|
||||
}
|
||||
|
||||
.accordion.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
margin-left: 1px;
|
||||
|
||||
&:not(.no-caret) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
|
||||
&:before {
|
||||
content: "\f0d7";
|
||||
font-family: FontAwesome;
|
||||
display: inline-block;
|
||||
|
||||
transform: rotate(-90deg);
|
||||
transition: .25s ease-in-out;
|
||||
}
|
||||
|
||||
&.open:before {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-content-container {
|
||||
overflow: auto;
|
||||
transition: max-height 0.25s ease-in-out;
|
||||
|
||||
@include hide-scrollbar;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="pos_hr.AccordionItem">
|
||||
<div class="accordion position-relative" t-att-class="{'disabled': props.disabled}">
|
||||
<button class="accordion-header dropdown-item" tabindex="0"
|
||||
t-att-class="{'open': state.open}"
|
||||
t-att-aria-expanded="state.open ? 'true' : 'false'"
|
||||
t-on-click="toggle"
|
||||
>
|
||||
<t t-slot="header"/>
|
||||
</button>
|
||||
<div t-ref="content_container" class="accordion-content-container" t-attf-style="max-height: {{state.open ? contentHeight : 0}}px;">
|
||||
<div class="accordion-content" >
|
||||
<t t-slot="content"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { Component } from "@odoo/owl";
|
||||
|
||||
export class QuantityButtons extends Component {
|
||||
static template = "point_of_sale.QuantityButtons";
|
||||
static props = {
|
||||
quantity: Number,
|
||||
setQuantity: Function,
|
||||
isPlusButtonDisabled: { type: Boolean, optional: true },
|
||||
btnClasses: { type: String, optional: true },
|
||||
};
|
||||
|
||||
changeQuantity(increment) {
|
||||
const isDisabled = increment == 1 && this.props.isPlusButtonDisabled;
|
||||
if (!isDisabled) {
|
||||
this.props.setQuantity(this.props.quantity + increment);
|
||||
}
|
||||
}
|
||||
|
||||
setQuantity(event) {
|
||||
const quantity = parseFloat(event.target.value);
|
||||
this.props.setQuantity(isNaN(quantity) ? 0 : quantity);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
input[name="pos_quantity"] {
|
||||
padding: 0;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
max-width: 3rem;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
max-width: 4rem;
|
||||
}
|
||||
|
||||
// removing input field=number arrows as their size might
|
||||
// change depending on browser default styling and shift input's position
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
&[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
}
|
||||
|
||||
.px-2-5 {
|
||||
padding-right: 0.75rem !important;
|
||||
padding-left: 0.75rem !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="point_of_sale.QuantityButtons">
|
||||
<div name="quantity_buttons_wrapper" class="input-group justify-content-end justify-content-md-center p-1 pt-0">
|
||||
<button
|
||||
t-attf-class="px-2-5 btn btn-secondary btn-sm {{ props.btnClasses or 'd-md-inline-block' }}"
|
||||
name="pos_quantity_button_minus"
|
||||
aria-label="Remove one"
|
||||
t-on-click.stop="() => this.changeQuantity(-1)">
|
||||
<i class="fa fa-minus"/>
|
||||
</button>
|
||||
<input
|
||||
class="form-control quantity text-center"
|
||||
name="pos_quantity"
|
||||
type="number"
|
||||
t-att-value="props.quantity"
|
||||
t-on-click.stop=""
|
||||
t-on-change="setQuantity"/>
|
||||
<button
|
||||
t-attf-class="px-2-5 btn btn-secondary btn-sm {{ props.btnClasses or 'd-md-inline-block' }}"
|
||||
name="pos_quantity_button_plus"
|
||||
aria-label="Add one"
|
||||
t-att-disabled="props.isPlusButtonDisabled"
|
||||
t-on-click.stop="() => this.changeQuantity(1)">
|
||||
<i class="fa fa-plus"/>
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import { Component } from "@odoo/owl";
|
||||
import { usePos } from "@point_of_sale/app/hooks/pos_hook";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { pick } from "@web/core/utils/objects";
|
||||
|
||||
export class CategorySelector extends Component {
|
||||
static template = "point_of_sale.CategorySelector";
|
||||
static props = {};
|
||||
|
||||
setup() {
|
||||
this.ui = useService("ui");
|
||||
this.pos = usePos();
|
||||
}
|
||||
|
||||
getCategoriesList(list, allParents, depth) {
|
||||
const categoriesList = [...list];
|
||||
list.forEach((item) => {
|
||||
if (item.id === allParents[depth]?.id && item.child_ids?.length) {
|
||||
categoriesList.push(
|
||||
...this.getCategoriesList(item.child_ids, allParents, depth + 1)
|
||||
);
|
||||
}
|
||||
});
|
||||
return categoriesList;
|
||||
}
|
||||
|
||||
getCategoriesAndSub() {
|
||||
const { limit_categories, iface_available_categ_ids } = this.pos.config;
|
||||
let rootCategories = this.pos.models["pos.category"].getAll();
|
||||
if (limit_categories && iface_available_categ_ids.length > 0) {
|
||||
rootCategories = iface_available_categ_ids;
|
||||
}
|
||||
rootCategories = rootCategories
|
||||
.filter((category) => !category.parent_id)
|
||||
.sort((a, b) => a.sequence - b.sequence);
|
||||
const selected = this.pos.selectedCategory ? [this.pos.selectedCategory] : [];
|
||||
const allParents = selected.concat(this.pos.selectedCategory?.allParents || []).reverse();
|
||||
return this.getCategoriesList(rootCategories, allParents, 0)
|
||||
.flat(Infinity)
|
||||
.filter((c) => c.hasProductsToShow)
|
||||
.map(this.getChildCategoriesInfo, this);
|
||||
}
|
||||
|
||||
getAncestorsAndCurrent() {
|
||||
const selectedCategory = this.pos.selectedCategory;
|
||||
return selectedCategory
|
||||
? [undefined, ...selectedCategory.allParents, selectedCategory]
|
||||
: [selectedCategory];
|
||||
}
|
||||
|
||||
getChildCategoriesInfo(category) {
|
||||
return {
|
||||
...pick(category, "id", "name", "color"),
|
||||
imgSrc:
|
||||
this.pos.config.show_category_images && category.has_image
|
||||
? `/web/image?model=pos.category&field=image_128&id=${category.id}`
|
||||
: undefined,
|
||||
isSelected: this.getAncestorsAndCurrent().includes(category),
|
||||
isChildren: this.getChildCategories(this.pos.selectedCategory).includes(category),
|
||||
};
|
||||
}
|
||||
|
||||
getChildCategories(selectedCategory) {
|
||||
return selectedCategory
|
||||
? [...selectedCategory.child_ids]
|
||||
: this.pos.models["pos.category"].filter((category) => !category.parent_id);
|
||||
}
|
||||
|
||||
getAllSelected() {
|
||||
return this.getAncestorsAndCurrent().filter(Boolean).length === 0;
|
||||
}
|
||||
hasParent() {
|
||||
const selectedCategory = this.pos.selectedCategory;
|
||||
return !!(selectedCategory && selectedCategory.parent_id);
|
||||
}
|
||||
isAncestorOrSelected(category) {
|
||||
const selected = this.pos.selectedCategory;
|
||||
if (!selected) {
|
||||
return false;
|
||||
}
|
||||
return category.id === selected.id || selected.allParents.some((p) => p.id === category.id);
|
||||
}
|
||||
|
||||
showCategoryImg(category) {
|
||||
return this.pos.config.show_category_images && category.imgSrc && !this.ui.isSmall;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
.category-list {
|
||||
grid-template-columns: repeat(auto-fill, minmax(115px, 1fr));
|
||||
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
margin-bottom: map-get($spacers, 2);
|
||||
max-height: 16.5rem;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
max-height: 11rem;
|
||||
}
|
||||
}
|
||||
|
||||
.category-button {
|
||||
--btn-border-color: #{$o-gray-200};
|
||||
border-width: 2px;
|
||||
height: 4rem;
|
||||
|
||||
.line-clamp-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="point_of_sale.CategorySelector">
|
||||
<div t-attf-class="{{this.pos.config.show_category_images ? 'category-list' : 'product-list'}} d-grid gap-1 gap-lg-2 p-2">
|
||||
<t t-foreach="this.getCategoriesAndSub()" t-as="category" t-key="category.id">
|
||||
<button t-on-click="() => this.pos.setSelectedCategory(category.id)"
|
||||
t-attf-class="o_colorlist_item_color_{{category.color or 'none'}}"
|
||||
t-att-class="{
|
||||
'border-0': category.isChildren and !this.isAncestorOrSelected(category),
|
||||
'opacity-75 border-0': !category.isChildren and !category.isSelected,
|
||||
'justify-content-center': ui.isSmall
|
||||
}"
|
||||
class="category-button p-1 btn btn-light d-flex justify-content-around align-items-center rounded-3 gap-1">
|
||||
<div t-if="showCategoryImg(category)" class="overflow-hidden flex-shrink-0 ratio ratio-1x1" style="width:40%;">
|
||||
<img t-if="category.imgSrc and !ui.isSmall" t-att-src="category.imgSrc"
|
||||
class="category-img-thumb h-100 rounded-3 object-fit-cover"
|
||||
alt="Category"
|
||||
/>
|
||||
</div>
|
||||
<div class="line-clamp-3" t-att-class="{'w-100': !showCategoryImg(category)}" t-att-style="{'width: 60%;': showCategoryImg(category)}">
|
||||
<span t-if="category.name" class="text-center" t-esc="category.name" />
|
||||
</div>
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||