diff --git a/pos_multi_variant/__init__.py b/pos_multi_variant/__init__.py index 727eb6127..cbad9d814 100644 --- a/pos_multi_variant/__init__.py +++ b/pos_multi_variant/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + ############################################################################# # # Cybrosys Technologies Pvt. Ltd. @@ -19,4 +20,5 @@ # If not, see . # ############################################################################# + from . import models diff --git a/pos_multi_variant/__manifest__.py b/pos_multi_variant/__manifest__.py index ac06c2618..8df4284b0 100644 --- a/pos_multi_variant/__manifest__.py +++ b/pos_multi_variant/__manifest__.py @@ -21,7 +21,7 @@ ############################################################################# { 'name': "POS Product Multi variant", - 'version': '16.0.1.0.0', + 'version': '16.0.1.0.1', 'category': 'Point of Sale', 'summary': """POS Multi-variant module is an advanced way for managing product variants from the point of sale application""", diff --git a/pos_multi_variant/doc/RELEASE_NOTES.md b/pos_multi_variant/doc/RELEASE_NOTES.md index 943eb5d86..d60724117 100755 --- a/pos_multi_variant/doc/RELEASE_NOTES.md +++ b/pos_multi_variant/doc/RELEASE_NOTES.md @@ -6,4 +6,7 @@ - Initial commit for POS Product Multi variant - +#### 14.01.2025 +#### Version 16.0.1.0.1 +##### ADD +- Fixed issue related to the amount total in pos orders. \ No newline at end of file diff --git a/pos_multi_variant/models/__init__.py b/pos_multi_variant/models/__init__.py index 3cb2769c0..3b765088a 100644 --- a/pos_multi_variant/models/__init__.py +++ b/pos_multi_variant/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + ############################################################################# # # Cybrosys Technologies Pvt. Ltd. @@ -19,6 +20,7 @@ # If not, see . # ############################################################################# + from . import product_template from . import pos_session from . import variants_tree diff --git a/pos_multi_variant/models/pos_session.py b/pos_multi_variant/models/pos_session.py index 66ae666b0..fea407b63 100644 --- a/pos_multi_variant/models/pos_session.py +++ b/pos_multi_variant/models/pos_session.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + ############################################################################# # # Cybrosys Technologies Pvt. Ltd. @@ -19,6 +20,7 @@ # If not, see . # ############################################################################# + from odoo import models diff --git a/pos_multi_variant/models/product_template.py b/pos_multi_variant/models/product_template.py index fe89de6cd..e39083f51 100644 --- a/pos_multi_variant/models/product_template.py +++ b/pos_multi_variant/models/product_template.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + ############################################################################# # # Cybrosys Technologies Pvt. Ltd. @@ -19,6 +20,7 @@ # If not, see . # ############################################################################# + from odoo import fields, models diff --git a/pos_multi_variant/models/variants_tree.py b/pos_multi_variant/models/variants_tree.py index c90a782f7..5bbad8b98 100644 --- a/pos_multi_variant/models/variants_tree.py +++ b/pos_multi_variant/models/variants_tree.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + ############################################################################# # # Cybrosys Technologies Pvt. Ltd. @@ -19,6 +20,7 @@ # If not, see . # ############################################################################# + from odoo import fields, models diff --git a/pos_multi_variant/static/src/css/label.css b/pos_multi_variant/static/src/css/label.css index 977f72571..8348e398f 100644 --- a/pos_multi_variant/static/src/css/label.css +++ b/pos_multi_variant/static/src/css/label.css @@ -38,6 +38,24 @@ position: absolute; background-color:#d7d7d7; font-style: italic; } + +.multi_variant { + position: absolute; + top: 51px; + left: 10px; + padding: 5px 10px; + background-color: #007bff; + color: white; + font-size: 12px; + font-weight: bold; + border-radius: 3px; + border: 1px solid #0056b3; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + text-transform: uppercase; + cursor: default; + white-space: nowrap; + } + .variant-selected{ position: absolute; bottom: 23px; @@ -64,4 +82,140 @@ font-style: italic; justify-content: center; align-items: center; color: #03001C; +} + +.pos_multi_variant .product-category { + padding: 0.4rem 0; + max-width: 1200px; + margin: 0 auto; +} + +.pos_multi_variant .category-title { + font-size: 1.8rem; + color: #333; + margin-bottom: 1.5rem; + text-align: center; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.pos_multi_variant .product-grid { + display: grid; + /* Three items per row by default */ + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + padding: 0 1rem; + margin: 0 auto; + max-width: 1000px; +} + +.pos_multi_variant .product-card { + position: relative; + background: white; + border-radius: 12px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; + overflow: hidden; + cursor: pointer; + width: 100%; +} + +.pos_multi_variant .product-card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15); +} + +.pos_multi_variant .product-image { + position: relative; + width: 100%; + padding-top: 100%; /* 1:1 Aspect Ratio */ + overflow: hidden; +} + +.pos_multi_variant .product-image img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease; +} + +.pos_multi_variant .product-card:hover .product-image img { + transform: scale(1.05); +} + +.pos_multi_variant .ribbon { + position: absolute; + top: 20px; + left: -5px; + background: #40bb4e; + color: white; + padding: 8px 20px; + font-size: 0.85rem; + font-weight: 600; + text-transform: uppercase; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + z-index: 100; + clip-path: polygon(0 0, 100% 0, calc(100% - 10px) 100%, 0 100%, 10px 50%); +} + +.pos_multi_variant .price-tag { + position: absolute; + bottom: 60px; + right: 10px; + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 5px 10px; + border-radius: 20px; + font-size: 0.9rem; + font-weight: 500; +} + +.pos_multi_variant .variant-name { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, 0.7); + color: white; + padding: 12px; + text-align: center; + font-size: 1rem; + font-weight: 500; +} + +.pos_multi_variant .section-divider { + border: none; + height: 1px; + background: linear-gradient(to right, transparent, #ddd, transparent); + margin: 2rem 0; +} + +/* Tablet view - 2 items per row */ +@media (max-width: 900px) { + .pos_multi_variant .product-grid { + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; + padding: 0 1rem; + } + + .pos_multi_variant .category-title { + font-size: 1.5rem; + } +} + +/* Mobile view - 1 item per row */ +@media (max-width: 600px) { + .pos_multi_variant .product-grid { + grid-template-columns: 1fr; + gap: 1rem; + } + + .pos_multi_variant .product-card { + max-width: 350px; + margin: 0 auto; + } } \ No newline at end of file diff --git a/pos_multi_variant/static/src/js/ProductPopup.js b/pos_multi_variant/static/src/js/ProductPopup.js index 7db458c1f..b99cedbad 100644 --- a/pos_multi_variant/static/src/js/ProductPopup.js +++ b/pos_multi_variant/static/src/js/ProductPopup.js @@ -1,75 +1,57 @@ -odoo.define('pos_multi_variant.ProductsPopup', function(require) { - 'use strict'; - /* This JavaScript code defines the ProductsPopup component, which extends - * the ProductItem class from the point_of_sale module. It represents a popup - * for selecting product variants. - */ - const Registries = require('point_of_sale.Registries'); - const { useListener } = require("@web/core/utils/hooks"); - const ProductItem = require('point_of_sale.ProductItem'); +/** @odoo-module **/ - class ProductsPopup extends ProductItem { - setup() { - super.setup(); - useListener('click','.confirm', this.click_confirm); - useListener('click','.product', this.select_variant); - useListener('click','.cancel', this.click_cancel); - } - select_variant(e) { - var order = this.env.pos.get_order() - var self = e.composedPath ? e.composedPath()[2] : e.path[2]; - var action = $(self).find('.action').text(); - var category = $(self).find('.action').data('category'); - $('.product-img').find('.variant-selected').each(function () - { if($(this).data('category') == category) - { $(this).text("").removeClass('variant-selected'); - $(self).find('.action').text("Selected").addClass('variant-selected'); - } - }); - $(self).find('.action').text("Selected").addClass('variant-selected'); - var add = $(self).find('.extra-price').text().substr(1).slice(0, -2); - var type = $(self).find('.variants').text(); - $(self).find('.variant-selected').attr('data-price', add); - $(self).find('.variant-selected').attr('data-type', type); - } - click_confirm(e){ - var price = 0.00 - var order = this.env.pos.get_order() - var selected_orderline = order.get_selected_orderline() - var variants = [] - this.env.pos.selectedOrder.selected_orderline.product_variants=variants - $('.product-img').find('.variant-selected').each(function () - { - var add = this.previousSibling.innerHTML; - add = add.slice(3) - price += parseFloat(add) - if (order.selected_orderline.product.is_pos_variants){ - variants.push({ - 'extra_price': add, - 'type': $(this).data('type'), - }) - }; - }) - selected_orderline.price_manually_set = true; - selected_orderline.price += price - this.env.posbus.trigger('close-popup', { - popupId: this.props.id - }); - } - click_cancel(){ - this.env.posbus.trigger('close-popup', { - popupId: this.props.id - }); - } - imageUrl() { - return `/web/image?model=product.product&field=image_1920&id=${this.props.product_tmpl_id}&unique=1`; +import Registries from 'point_of_sale.Registries'; +import { useListener } from "@web/core/utils/hooks"; +const ProductItem = require('point_of_sale.ProductItem'); +const { useState } = owl; + + +class ProductsPopup extends ProductItem { + setup() { + super.setup(); + this.state = useState({ + variant_details: this.props.variant_details, + selected_variants: {}, + price_total: {}, + }) + } + + SelectVariant(product,variant) { + if (this.state.selected_variants[product.attribute_id[1]] === variant.id){ + this.state.selected_variants[product.attribute_id[1]] = false + this.state.price_total[product.attribute_id[1]] = 0.0 } - async _clickProduct(event) { + else{ + this.state.selected_variants[product.attribute_id[1]] = variant.id + this.state.price_total[product.attribute_id[1]] = product.extra_price } } - ProductsPopup.template = 'ProductsPopUp'; - ProductsPopup.defaultProps = {}; - Registries.Component.add(ProductsPopup); - return ProductsPopup; -}); + clickConfirm(e){ + const total = Object.values(this.state.price_total).reduce((sum, value) => sum + value, 0); + var order = this.env.pos.get_order() + var selected_orderline = order.get_selected_orderline() + selected_orderline.price += total + this.env.posbus.trigger('close-popup', { + popupId: this.props.id + }); + } + clickCancel(){ + this.env.pos.get_order().orderlines.remove(this.env.pos.get_order().selected_orderline) + this.env.posbus.trigger('close-popup', { + popupId: this.props.id + }); + } + + imageUrl() { + return `/web/image?model=product.product&field=image_1920&id=${this.props.product_tmpl_id}&unique=1`; + } + + getSelected(attr, variant) { + return this.state.selected_variants[attr] === variant.id + } + +} +ProductsPopup.template = 'ProductsPopUp'; +ProductsPopup.defaultProps = {}; +Registries.Component.add(ProductsPopup); diff --git a/pos_multi_variant/static/src/js/ProductScreen.js b/pos_multi_variant/static/src/js/ProductScreen.js index 660e73323..0087e1a55 100644 --- a/pos_multi_variant/static/src/js/ProductScreen.js +++ b/pos_multi_variant/static/src/js/ProductScreen.js @@ -1,62 +1,59 @@ -odoo.define('pos_multi_variant.ProductScreen', function(require) { - 'use strict'; - /* This JavaScript code extends the ProductScreen class from the point_of_sale module. - * It adds functionality for handling product clicks and displaying the ProductsPopup - * for selecting variants. - */ - var ProductScreen = require('point_of_sale.ProductScreen'); - const Registries = require('point_of_sale.Registries'); - const NumberBuffer = require('point_of_sale.NumberBuffer'); - var rpc = require('web.rpc'); - const ProductScreenExtend = (ProductScreen) => - class extends ProductScreen { - constructor() { - super(...arguments); +/** @odoo-module **/ + +import ProductScreen from 'point_of_sale.ProductScreen'; +import Registries from 'point_of_sale.Registries'; +import NumberBuffer from 'point_of_sale.NumberBuffer'; +import rpc from 'web.rpc'; + +const ProductScreenExtend = (ProductScreen) => +class extends ProductScreen { + setup() { + super.setup(); + } + + async _clickProduct(event) { + await super._clickProduct(...arguments) + if (!this.currentOrder) { + this.env.pos.add_new_order(); } - async _clickProduct(event) { - await super._clickProduct(...arguments) - if (!this.currentOrder) { - this.env.pos.add_new_order(); - } - const product = event.detail; - var variant_product = '' - await rpc.query({ - model: 'variants.tree', - method: 'search_read', - fields: ['extra_price','attribute_id','value_ids', 'variants_id'], - args: [[['variants_id','=',event.detail.product_tmpl_id]]] - }).then(function (data) { - variant_product = data - }); - var li=[] - for(var i=0; i class VariantsPosGlobalState extends PosGlobalState { - async _processData(loadedData) { +/** @odoo-module **/ - await super._processData(...arguments); +import { PosGlobalState } from 'point_of_sale.models'; +import Registries from 'point_of_sale.Registries'; - this.variants_tree = loadedData['variants.tree']; - this.product_attribute_value = loadedData['product.attribute.value']; - } +const VariantsPosGlobalState = (PosGlobalState) => class VariantsPosGlobalState extends PosGlobalState { + async _processData(loadedData) { + + await super._processData(...arguments); + + this.variants_tree = loadedData['variants.tree']; + this.product_attribute_value = loadedData['product.attribute.value']; } - Registries.Model.extend(PosGlobalState, VariantsPosGlobalState); -}); +} +Registries.Model.extend(PosGlobalState, VariantsPosGlobalState); diff --git a/pos_multi_variant/static/src/js/product_variant_orderline.js b/pos_multi_variant/static/src/js/product_variant_orderline.js index 4fdf5c644..82600904a 100644 --- a/pos_multi_variant/static/src/js/product_variant_orderline.js +++ b/pos_multi_variant/static/src/js/product_variant_orderline.js @@ -1,34 +1,23 @@ -odoo.define('pos_order_question.Orderline', function(require) { - 'use strict'; - /* This JavaScript code defines the PosMultiVariantOrderline class - * extending the Orderline class from the point_of_sale.models module. - * It adds additional functionality related to product variants. - */ - var { - Orderline, - } = require('point_of_sale.models'); - var utils = require('web.utils'); - const Registries = require('point_of_sale.Registries'); +/** @odoo-module **/ - const PosMultiVariantOrderline = (Orderline) => class PosMultiVariantOrderline extends Orderline { +import { Orderline } from 'point_of_sale.models'; +import Registries from 'point_of_sale.Registries'; - constructor(obj, options) { - super(...arguments); - this.product_variants = this.product_variants || []; - } - export_as_JSON() { - const json = super.export_as_JSON(...arguments); - json.product_variants = this.product_variants || []; - return json; - } - export_for_printing() { - var line = super.export_for_printing(...arguments); - line.product_variants = this.product_variants; - return line; - } +export const PosMultiVariantOrderline = (Orderline) => class PosMultiVariantOrderline extends Orderline { + constructor(obj, options) { + super(...arguments); + this.product_variants = this.product_variants || []; } - Registries.Model.extend(Orderline, PosMultiVariantOrderline); -}); - - + export_as_JSON() { + const json = super.export_as_JSON(...arguments); + json.product_variants = this.product_variants || []; + return json; + } + export_for_printing() { + var line = super.export_for_printing(...arguments); + line.product_variants = this.product_variants; + return line; + } +} +Registries.Model.extend(Orderline, PosMultiVariantOrderline); diff --git a/pos_multi_variant/static/src/xml/label.xml b/pos_multi_variant/static/src/xml/label.xml index b77b82001..91ecd0d69 100644 --- a/pos_multi_variant/static/src/xml/label.xml +++ b/pos_multi_variant/static/src/xml/label.xml @@ -2,10 +2,9 @@ - + - Multi-variant - + Multi-variant diff --git a/pos_multi_variant/static/src/xml/popup.xml b/pos_multi_variant/static/src/xml/popup.xml index 99c12b9b6..8a3cea5d5 100644 --- a/pos_multi_variant/static/src/xml/popup.xml +++ b/pos_multi_variant/static/src/xml/popup.xml @@ -1,57 +1,53 @@ - -