[IMP] point_of_sale: Allow products to be part of multiple pos categories
Currently, a product can only be part of one `pos_category`. This PR changes the relationship between the `product` and the `pos_category` from a `One2many` to a `Many2many`. closes odoo/odoo#122907 Task: 3138825 Related: odoo/enterprise#41791 Related: odoo/upgrade#4739 Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
@@ -40,14 +40,14 @@
|
||||
<record id="preparation_printer" model="pos.printer">
|
||||
<field name="name">Preparation Printer</field>
|
||||
<field name="proxy_ip">localhost</field>
|
||||
<field name="product_categories_ids" eval="[(6, 0, [ref('point_of_sale.pos_category_miscellaneous')])]" />
|
||||
<field name="product_categories_ids" eval="[(6, 0, [ref('point_of_sale.pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
|
||||
<!-- Resource: product.product -->
|
||||
<record id="stock.product_cable_management_box" model="product.product">
|
||||
<field name="pos_categ_id" ref="point_of_sale.pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('point_of_sale.pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="wall_shelf" model="product.product">
|
||||
<record id="wall_shelf" model="product.product">
|
||||
<field name="available_in_pos">True</field>
|
||||
<field name="list_price">1.98</field>
|
||||
<field name="name">Wall Shelf Unit</field>
|
||||
@@ -56,11 +56,11 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="barcode">2100002000003</field>
|
||||
<field name="taxes_id" eval='[(5,)]'/>
|
||||
<field name="taxes_id" eval="[(5,)]"/>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/wall_shelf_unit.png"/>
|
||||
</record>
|
||||
<record id="small_shelf" model="product.product">
|
||||
@@ -70,12 +70,12 @@
|
||||
<field name="default_code">FURN_0008</field>
|
||||
<field name="type">product</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="taxes_id" eval='[(5,)]'/>
|
||||
<field name="taxes_id" eval="[(5,)]"/>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/small_shelf.png"/>
|
||||
</record>
|
||||
|
||||
@@ -88,9 +88,9 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/letter_tray.png"/>
|
||||
</record>
|
||||
<record id="desk_organizer" model="product.product">
|
||||
@@ -103,11 +103,11 @@
|
||||
<field name="type">product</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/desk_organizer.png"/>
|
||||
<field name="taxes_id" eval='[(5,)]'/> <!-- no taxes -->
|
||||
<field name="taxes_id" eval="[(5,)]"/> <!-- no taxes -->
|
||||
</record>
|
||||
|
||||
<function model="ir.model.data" name="_update_xmlids">
|
||||
@@ -183,9 +183,9 @@
|
||||
<field name="barcode">2301000000006</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/magnetic_board.png"/>
|
||||
</record>
|
||||
<record id="monitor_stand" model="product.product">
|
||||
@@ -197,9 +197,9 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/monitor_stand.png"/>
|
||||
</record>
|
||||
<record id="desk_pad" model="product.product">
|
||||
@@ -211,9 +211,9 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/desk_pad.png"/>
|
||||
</record>
|
||||
|
||||
@@ -225,8 +225,8 @@
|
||||
<field name="type">product</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/whiteboard.png"/>
|
||||
</record>
|
||||
|
||||
@@ -239,9 +239,9 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/led_lamp.png"/>
|
||||
</record>
|
||||
|
||||
@@ -255,9 +255,9 @@
|
||||
<field name="to_weight">True</field>
|
||||
<field name="barcode">2100001000004</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/newspaper_stand.png"/>
|
||||
</record>
|
||||
|
||||
@@ -269,114 +269,114 @@
|
||||
<field name="default_code">CONS_0001</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_consumable"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/whiteboard_pen.png"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_1" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_2" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_01" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_chairs"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_02" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_order_01" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_3" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_4_product_template" model="product.template">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_5" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_6" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_7" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_8" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_9" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_10" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_11" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_chairs"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_11b" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_chairs"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_12" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_chairs"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_13" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_16" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_20" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_22" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_24" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_25" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_27" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_03" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_desks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_02" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_01" model="product.product">
|
||||
<field name="available_in_pos" eval="True"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="barcode">2100002000003</field>
|
||||
<field name="taxes_id" eval='[(5,)]'/>
|
||||
<field name="taxes_id" eval="[(5,)]"/>
|
||||
<field name="categ_id" ref="product.product_category_1"/>
|
||||
<field name="pos_categ_id" ref="pos_category_furniture"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_furniture')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/wall_shelf_unit.png"/>
|
||||
</record>
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
<field name="default_code">FURN_0008</field>
|
||||
<field name="type">product</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="taxes_id" eval='[(5,)]'/>
|
||||
<field name="taxes_id" eval="[(5,)]"/>
|
||||
<field name="categ_id" ref="product.product_category_1"/>
|
||||
<field name="pos_categ_id" ref="pos_category_furniture"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_furniture')])]"/>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/small_shelf.png"/>
|
||||
</record>
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
<field name="weight">0.01</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_1"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/monitor_stand.png"/>
|
||||
</record>
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
<field name="type">product</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="categ_id" ref="product.product_category_1"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/desk_organizer.png"/>
|
||||
</record>
|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
<field name="default_code">CONS_0001</field>
|
||||
<field name="to_weight">True</field>
|
||||
<field name="categ_id" ref="product.product_category_1"/>
|
||||
<field name="pos_categ_id" ref="pos_category_miscellaneous"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit" />
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit" />
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('pos_category_miscellaneous')])]"/>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="image_1920" type="base64" file="point_of_sale/static/img/whiteboard_pen.png"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from typing import List, Tuple
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
@@ -24,14 +27,13 @@ class PosCategory(models.Model):
|
||||
# field to determine whether a pos.category has an image or not.
|
||||
has_image = fields.Boolean(compute='_compute_has_image')
|
||||
|
||||
def name_get(self):
|
||||
def get_names(cat):
|
||||
res = []
|
||||
while cat:
|
||||
res.append(cat.name)
|
||||
cat = cat.parent_id
|
||||
return res
|
||||
return [(cat.id, " / ".join(reversed(get_names(cat)))) for cat in self if cat.name]
|
||||
def _get_hierarchy(self) -> List[str]:
|
||||
""" Returns a list representing the hierarchy of the categories. """
|
||||
self.ensure_one()
|
||||
return (self.parent_id._get_hierarchy() if self.parent_id else []) + [self.name]
|
||||
|
||||
def name_get(self) -> List[Tuple[int, str]]:
|
||||
return [(category.id, " / ".join(category._get_hierarchy())) for category in self if category.name]
|
||||
|
||||
@api.ondelete(at_uninstall=False)
|
||||
def _unlink_except_session_open(self):
|
||||
|
||||
@@ -654,7 +654,10 @@ class PosConfig(models.Model):
|
||||
t.available_in_pos
|
||||
AND t.sale_ok
|
||||
AND (t.company_id=%(company_id)s OR t.company_id IS NULL)
|
||||
AND %(available_categ_ids)s IS NULL OR t.pos_categ_id=ANY(%(available_categ_ids)s)
|
||||
AND (%(available_categ_ids)s IS NULL OR EXISTS (
|
||||
SELECT 1 FROM pos_category_product_template_rel
|
||||
WHERE product_template_id = t.id
|
||||
AND pos_category_id = ANY(%(available_categ_ids)s)))
|
||||
) OR p.id=%(tip_product_id)s
|
||||
ORDER BY t.priority DESC,
|
||||
t.detailed_type DESC,
|
||||
|
||||
@@ -1913,7 +1913,7 @@ class PosSession(models.Model):
|
||||
('company_id', '=', self.config_id.company_id.id), ('company_id', '=', False)
|
||||
]
|
||||
if self.config_id.limit_categories and self.config_id.iface_available_categ_ids:
|
||||
domain = AND([domain, [('pos_categ_id', 'in', self.config_id.iface_available_categ_ids.ids)]])
|
||||
domain = AND([domain, [('pos_categ_ids', 'in', self.config_id.iface_available_categ_ids.ids)]])
|
||||
if self.config_id.iface_tipproduct:
|
||||
domain = OR([domain, [('id', '=', self.config_id.tip_product_id.id)]])
|
||||
|
||||
@@ -1921,7 +1921,7 @@ class PosSession(models.Model):
|
||||
'search_params': {
|
||||
'domain': domain,
|
||||
'fields': [
|
||||
'display_name', 'lst_price', 'standard_price', 'categ_id', 'pos_categ_id', 'taxes_id', 'barcode',
|
||||
'display_name', 'lst_price', 'standard_price', 'categ_id', 'pos_categ_ids', 'taxes_id', 'barcode',
|
||||
'default_code', 'to_weight', 'uom_id', 'description_sale', 'description', 'product_tmpl_id', 'tracking',
|
||||
'write_date', 'available_in_pos', 'attribute_line_ids', 'active', 'image_128'
|
||||
],
|
||||
@@ -2049,42 +2049,6 @@ class PosSession(models.Model):
|
||||
|
||||
return amount
|
||||
|
||||
def get_total_sold_refund_per_category(self, group_by_user_id=None):
|
||||
total_sold_per_user_per_category = {}
|
||||
total_refund_per_user_per_category = {}
|
||||
|
||||
for order in self.order_ids:
|
||||
if group_by_user_id:
|
||||
user_id = order.user_id.id
|
||||
else:
|
||||
# use a user_id of 0 to keep the logic between with user group and without user group the same
|
||||
user_id = 0
|
||||
|
||||
if user_id not in total_sold_per_user_per_category:
|
||||
total_sold_per_user_per_category[user_id] = {}
|
||||
total_refund_per_user_per_category[user_id] = {}
|
||||
|
||||
total_sold_per_category = total_sold_per_user_per_category[user_id]
|
||||
total_refund_per_category = total_refund_per_user_per_category[user_id]
|
||||
|
||||
for line in order.lines:
|
||||
key = line.product_id.pos_categ_id.name or "None"
|
||||
if line.qty >= 0:
|
||||
if key in total_sold_per_category:
|
||||
total_sold_per_category[key] += line.price_subtotal_incl
|
||||
else:
|
||||
total_sold_per_category[key] = line.price_subtotal_incl
|
||||
else:
|
||||
if key in total_refund_per_category:
|
||||
total_refund_per_category[key] += line.price_subtotal_incl
|
||||
else:
|
||||
total_refund_per_category[key] = line.price_subtotal_incl
|
||||
|
||||
if group_by_user_id or not total_sold_per_user_per_category:
|
||||
return list(total_sold_per_user_per_category.items()), list(total_refund_per_user_per_category.items())
|
||||
else:
|
||||
return list(total_sold_per_user_per_category[0].items()), list(total_refund_per_user_per_category[0].items())
|
||||
|
||||
def get_pos_ui_product_pricelists_by_ids(self, pricelist_ids):
|
||||
params = self._loader_params_product_pricelist()
|
||||
params['search_params']['domain'] = [('id', 'in', pricelist_ids)]
|
||||
|
||||
@@ -12,7 +12,7 @@ class ProductTemplate(models.Model):
|
||||
|
||||
available_in_pos = fields.Boolean(string='Available in POS', help='Check if you want this product to appear in the Point of Sale.', default=False)
|
||||
to_weight = fields.Boolean(string='To Weigh With Scale', help="Check if the product should be weighted using the hardware scale integration.")
|
||||
pos_categ_id = fields.Many2one(
|
||||
pos_categ_ids = fields.Many2many(
|
||||
'pos.category', string='Point of Sale Category',
|
||||
help="Category used in the Point of Sale.")
|
||||
|
||||
|
||||
@@ -272,11 +272,12 @@ class ReportSaleDetails(models.AbstractModel):
|
||||
}
|
||||
|
||||
def _get_products_and_taxes_dict(self, line, products, taxes, currency):
|
||||
key1 = line.product_id.product_tmpl_id.pos_categ_id.name
|
||||
key2 = (line.product_id, line.price_unit, line.discount)
|
||||
products.setdefault(key1, {})
|
||||
products[key1].setdefault(key2, 0.0)
|
||||
products[key1][key2] += line.qty
|
||||
keys1 = line.product_id.product_tmpl_id.pos_categ_ids.mapped("name")
|
||||
for key1 in keys1:
|
||||
products.setdefault(key1, {})
|
||||
products[key1].setdefault(key2, 0.0)
|
||||
products[key1][key2] += line.qty
|
||||
|
||||
if line.tax_ids_after_fiscal_position:
|
||||
line_taxes = line.tax_ids_after_fiscal_position.sudo().compute_all(line.price_unit * (1-(line.discount or 0.0)/100.0), currency, line.qty, product=line.product_id, partner=line.order_id.partner_id or False)
|
||||
@@ -293,17 +294,20 @@ class ReportSaleDetails(models.AbstractModel):
|
||||
def _get_total_and_qty_per_category(self, categories):
|
||||
all_qty = 0
|
||||
all_total = 0
|
||||
total = lambda product: (product['quantity'] * product['price_unit']) * (100 - product['discount']) / 100
|
||||
for category_dict in categories:
|
||||
qty_cat = 0
|
||||
total_cat = 0
|
||||
for product in category_dict['products']:
|
||||
qty_cat += product['quantity']
|
||||
total_cat += (product['quantity'] * product['price_unit']) * (100 - product['discount']) / 100
|
||||
product['total_paid'] = (product['quantity'] * product['price_unit']) * (100 - product['discount']) / 100
|
||||
product['total_paid'] = total(product)
|
||||
total_cat += product['total_paid']
|
||||
category_dict['total'] = total_cat
|
||||
category_dict['qty'] = qty_cat
|
||||
all_qty += qty_cat
|
||||
all_total += total_cat
|
||||
# IMPROVEMENT: It would be better if the `products` are grouped by pos.order.line.id.
|
||||
unique_products = list({tuple(sorted(product.items())): product for category in categories for product in category['products']}.values())
|
||||
all_qty = sum([product['quantity'] for product in unique_products])
|
||||
all_total = sum([total(product) for product in unique_products])
|
||||
|
||||
return categories, {'total': all_total, 'qty': all_qty}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, tools
|
||||
from odoo import fields, models, tools
|
||||
|
||||
|
||||
class PosOrderReport(models.Model):
|
||||
@@ -32,7 +32,6 @@ class PosOrderReport(models.Model):
|
||||
product_categ_id = fields.Many2one('product.category', string='Product Category', readonly=True)
|
||||
invoiced = fields.Boolean(readonly=True)
|
||||
config_id = fields.Many2one('pos.config', string='Point of Sale', readonly=True)
|
||||
pos_categ_id = fields.Many2one('pos.category', string='PoS Category', readonly=True)
|
||||
pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', readonly=True)
|
||||
session_id = fields.Many2one('pos.session', string='Session', readonly=True)
|
||||
margin = fields.Float(string='Margin', readonly=True)
|
||||
@@ -62,7 +61,6 @@ class PosOrderReport(models.Model):
|
||||
pt.categ_id AS product_categ_id,
|
||||
p.product_tmpl_id,
|
||||
ps.config_id,
|
||||
pt.pos_categ_id,
|
||||
s.pricelist_id,
|
||||
s.session_id,
|
||||
s.account_move IS NOT NULL AS invoiced,
|
||||
@@ -88,7 +86,7 @@ class PosOrderReport(models.Model):
|
||||
s.user_id, s.company_id, s.sale_journal,
|
||||
s.pricelist_id, s.account_move, s.create_date, s.session_id,
|
||||
l.product_id,
|
||||
pt.categ_id, pt.pos_categ_id,
|
||||
pt.categ_id,
|
||||
p.product_tmpl_id,
|
||||
ps.config_id
|
||||
"""
|
||||
|
||||
@@ -133,17 +133,7 @@ export class PosDB {
|
||||
}
|
||||
make_ancestors(this.root_category_id, []);
|
||||
}
|
||||
category_contains(categ_id, product_id) {
|
||||
var product = this.product_by_id[product_id];
|
||||
if (product) {
|
||||
var cid = product.pos_categ_id[0];
|
||||
while (cid && cid !== categ_id) {
|
||||
cid = this.category_parent[cid];
|
||||
}
|
||||
return !!cid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* loads a record store from the database. returns default if nothing is found */
|
||||
load(store, deft) {
|
||||
if (CACHE[store] !== undefined) {
|
||||
@@ -193,33 +183,35 @@ export class PosDB {
|
||||
}
|
||||
if (product.available_in_pos) {
|
||||
var search_string = unaccent(this._product_search_string(product));
|
||||
var categ_id = product.pos_categ_id
|
||||
? product.pos_categ_id[0]
|
||||
: this.root_category_id;
|
||||
const all_categ_ids = product.pos_categ_ids.length
|
||||
? product.pos_categ_ids
|
||||
: [this.root_category_id];
|
||||
product.product_tmpl_id = product.product_tmpl_id[0];
|
||||
if (!stored_categories[categ_id]) {
|
||||
stored_categories[categ_id] = [];
|
||||
}
|
||||
stored_categories[categ_id].push(product.id);
|
||||
|
||||
if (this.category_search_string[categ_id] === undefined) {
|
||||
this.category_search_string[categ_id] = "";
|
||||
}
|
||||
this.category_search_string[categ_id] += search_string;
|
||||
|
||||
var ancestors = this.get_category_ancestors_ids(categ_id) || [];
|
||||
|
||||
for (var j = 0, jlen = ancestors.length; j < jlen; j++) {
|
||||
var ancestor = ancestors[j];
|
||||
if (!stored_categories[ancestor]) {
|
||||
stored_categories[ancestor] = [];
|
||||
for (const categ_id of all_categ_ids) {
|
||||
if (!stored_categories[categ_id]) {
|
||||
stored_categories[categ_id] = [];
|
||||
}
|
||||
stored_categories[ancestor].push(product.id);
|
||||
stored_categories[categ_id].push(product.id);
|
||||
|
||||
if (this.category_search_string[ancestor] === undefined) {
|
||||
this.category_search_string[ancestor] = "";
|
||||
if (this.category_search_string[categ_id] === undefined) {
|
||||
this.category_search_string[categ_id] = "";
|
||||
}
|
||||
this.category_search_string[categ_id] += search_string;
|
||||
|
||||
var ancestors = this.get_category_ancestors_ids(categ_id) || [];
|
||||
|
||||
for (var j = 0, jlen = ancestors.length; j < jlen; j++) {
|
||||
var ancestor = ancestors[j];
|
||||
if (!stored_categories[ancestor]) {
|
||||
stored_categories[ancestor] = [];
|
||||
}
|
||||
stored_categories[ancestor].push(product.id);
|
||||
|
||||
if (this.category_search_string[ancestor] === undefined) {
|
||||
this.category_search_string[ancestor] = "";
|
||||
}
|
||||
this.category_search_string[ancestor] += search_string;
|
||||
}
|
||||
this.category_search_string[ancestor] += search_string;
|
||||
}
|
||||
}
|
||||
this.product_by_id[product.id] = product;
|
||||
@@ -408,13 +400,18 @@ export class PosDB {
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
shouldAddProduct(product, list) {
|
||||
return product.active && product.available_in_pos && !list.includes(product);
|
||||
}
|
||||
|
||||
get_product_by_category(category_id) {
|
||||
var product_ids = this.product_by_category_id[category_id];
|
||||
var list = [];
|
||||
if (product_ids) {
|
||||
for (var i = 0, len = Math.min(product_ids.length, this.limit); i < len; i++) {
|
||||
const product = this.product_by_id[product_ids[i]];
|
||||
if (!(product.active && product.available_in_pos)) {
|
||||
if (!this.shouldAddProduct(product, list)) {
|
||||
continue;
|
||||
}
|
||||
list.push(product);
|
||||
@@ -441,7 +438,7 @@ export class PosDB {
|
||||
if (r) {
|
||||
var id = Number(r[1]);
|
||||
const product = this.get_product_by_id(id);
|
||||
if (!(product.active && product.available_in_pos)) {
|
||||
if (!this.shouldAddProduct(product, results)) {
|
||||
continue;
|
||||
}
|
||||
results.push(product);
|
||||
@@ -451,22 +448,41 @@ export class PosDB {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
/* from a product id, and a list of category ids, returns
|
||||
* true if the product belongs to one of the provided category
|
||||
/**
|
||||
* returns true if the product belongs to one of the provided categories
|
||||
* or one of its child categories.
|
||||
* @param {number[]} category_ids
|
||||
* @param {number} product_id
|
||||
* @returns {boolean}
|
||||
*/
|
||||
is_product_in_category(category_ids, product_id) {
|
||||
let cat = this.get_product_by_id(product_id).pos_categ_id[0];
|
||||
while (cat) {
|
||||
for (const cat_id of category_ids) {
|
||||
if (cat == cat_id) {
|
||||
// The == is important, ids may be strings
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cat = this.get_category_parent_id(cat);
|
||||
}
|
||||
return false;
|
||||
const product_categ_ids = this.get_product_by_id(product_id).pos_categ_ids;
|
||||
return this.any_of_is_subcategory(product_categ_ids, category_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively check if any of `subcategory_ids` belongs to any of the `category_ids`
|
||||
* @param {number[]} subcategory_ids
|
||||
* @param {number[]} category_ids
|
||||
* @returns {boolean}
|
||||
*/
|
||||
any_of_is_subcategory(subcategory_ids, category_ids) {
|
||||
return subcategory_ids.some((subcategory_id) =>
|
||||
this.is_subcategory(subcategory_id, category_ids)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Recursively check if a `subcategory_id` a child of any of the provided `category_ids`.
|
||||
* @param {number} subcategory_id
|
||||
* @param {number[]} category_ids
|
||||
* @returns {boolean}
|
||||
*/
|
||||
is_subcategory(subcategory_id, category_ids) {
|
||||
const check = (categ_id) => categ_id && this.is_subcategory(categ_id, category_ids);
|
||||
return (
|
||||
category_ids.includes(Number(subcategory_id)) ||
|
||||
check(this.get_category_parent_id(subcategory_id))
|
||||
);
|
||||
}
|
||||
|
||||
/* paid orders */
|
||||
|
||||
@@ -1638,8 +1638,10 @@ export class Order extends PosModel {
|
||||
const note = orderline.getNote();
|
||||
const productKey = `${product.id} - ${orderline.get_full_product_name()} - ${note}`;
|
||||
const lineKey = `${orderline.uuid} - ${note}`;
|
||||
|
||||
if (prepaCategoryIds.has(product.pos_categ_id[0]) || prepaCategoryIds.size === 0) {
|
||||
if (
|
||||
prepaCategoryIds.size === 0 ||
|
||||
this.pos.db.any_of_is_subcategory(product.pos_categ_ids, [...prepaCategoryIds])
|
||||
) {
|
||||
const quantity = orderline.get_quantity();
|
||||
const quantityDiff = oldChanges[lineKey]
|
||||
? quantity - oldChanges[lineKey].quantity
|
||||
@@ -1664,7 +1666,6 @@ export class Order extends PosModel {
|
||||
orderline.setHasChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether an orderline has been deleted from the order since it
|
||||
// was last sent to the preparation tools. If so we add this to the changes.
|
||||
for (const [lineKey, lineResume] of Object.entries(this.lastOrderPrepaChange)) {
|
||||
@@ -2266,26 +2267,6 @@ export class Order extends PosModel {
|
||||
|
||||
return fulldetails;
|
||||
}
|
||||
// Returns a total only for the orderlines with products belonging to the category
|
||||
get_total_for_category_with_tax(categ_id) {
|
||||
var total = 0;
|
||||
var self = this;
|
||||
|
||||
if (categ_id instanceof Array) {
|
||||
for (var i = 0; i < categ_id.length; i++) {
|
||||
total += this.get_total_for_category_with_tax(categ_id[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
this.orderlines.forEach(function (line) {
|
||||
if (self.pos.db.category_contains(categ_id, line.product.id)) {
|
||||
total += line.get_price_with_tax();
|
||||
}
|
||||
});
|
||||
|
||||
return total;
|
||||
}
|
||||
get_total_for_taxes(tax_id) {
|
||||
var total = 0;
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class TestPointOfSaleHttpCommon(AccountTestInvoicingHttpCommon):
|
||||
'taxes_id': False,
|
||||
'weight': 0.01,
|
||||
'to_weight': True,
|
||||
'pos_categ_id': pos_categ_misc.id,
|
||||
'pos_categ_ids': [(4, pos_categ_misc.id)],
|
||||
})
|
||||
cls.wall_shelf = env['product.product'].create({
|
||||
'name': 'Wall Shelf Unit',
|
||||
@@ -137,14 +137,14 @@ class TestPointOfSaleHttpCommon(AccountTestInvoicingHttpCommon):
|
||||
'available_in_pos': True,
|
||||
'list_price': 1.98,
|
||||
'taxes_id': False,
|
||||
'pos_categ_id': pos_categ_desks.id,
|
||||
'pos_categ_ids': [(4, pos_categ_desks.id)],
|
||||
})
|
||||
cls.letter_tray = env['product.product'].create({
|
||||
'name': 'Letter Tray',
|
||||
'available_in_pos': True,
|
||||
'list_price': 4.80,
|
||||
'taxes_id': False,
|
||||
'pos_categ_id': pos_categ_chairs.id,
|
||||
'pos_categ_ids': [(4, pos_categ_chairs.id)],
|
||||
})
|
||||
cls.desk_organizer = env['product.product'].create({
|
||||
'name': 'Desk Organizer',
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<filter name="filter_to_availabe_pos" string="Available in POS" domain="[('available_in_pos', '=', True)]"/>
|
||||
</filter>
|
||||
<filter name="categ_id" position="after">
|
||||
<filter string="POS Product Category" name="pos_categ_id" context="{'group_by':'pos_categ_id'}"/>
|
||||
<filter string="POS Product Category" name="pos_categ_ids" context="{'group_by':'pos_categ_ids'}"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
@@ -68,7 +68,7 @@
|
||||
<group name="pos" string="Point of Sale" attrs="{'invisible': [('sale_ok','=',False)]}">
|
||||
<field name="available_in_pos"/>
|
||||
<field name="to_weight" attrs="{'invisible': [('available_in_pos', '=', False)]}"/>
|
||||
<field name="pos_categ_id" attrs="{'invisible': [('available_in_pos', '=', False)]}" string="Category"/>
|
||||
<field name="pos_categ_ids" widget="many2many_tags" groups="point_of_sale.group_pos_user" attrs="{'invisible': [('available_in_pos', '=', False)]}" string="Category"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
@@ -122,7 +122,7 @@
|
||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="categ_id" position="before">
|
||||
<field name="pos_categ_id" optional="hide" string="POS Product Category"/>
|
||||
<field name="pos_categ_ids" widget="many2many_tags" groups="point_of_sale.group_pos_user" optional="hide" string="POS Product Category"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -133,7 +133,7 @@
|
||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="categ_id" position="before">
|
||||
<field name="pos_categ_id" optional="hide" string="POS Product Category"/>
|
||||
<field name="pos_categ_ids" widget="many2many_tags" groups="point_of_sale.group_pos_user" optional="hide" string="POS Product Category"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ****** Basic Restaurant Setup ***** -->
|
||||
@@ -22,7 +21,7 @@
|
||||
<field name="list_price">7.0</field>
|
||||
<field name="name">Margherita</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-pizza.png"/>
|
||||
</record>
|
||||
@@ -31,7 +30,7 @@
|
||||
<field name="list_price">7.0</field>
|
||||
<field name="name">Funghi</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-pizza.png"/>
|
||||
</record>
|
||||
@@ -40,7 +39,7 @@
|
||||
<field name="list_price">7.0</field>
|
||||
<field name="name">Vegetarian</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-pizza.png"/>
|
||||
</record>
|
||||
@@ -49,7 +48,7 @@
|
||||
<field name="list_price">4.5</field>
|
||||
<field name="name">Pasta Bolognese</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-pasta.jpg"/>
|
||||
</record>
|
||||
@@ -58,7 +57,7 @@
|
||||
<field name="list_price">5.5</field>
|
||||
<field name="name">Pasta 4 formaggi </field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-pasta-4f.jpg"/>
|
||||
</record>
|
||||
@@ -67,7 +66,7 @@
|
||||
<field name="list_price">7.5</field>
|
||||
<field name="name">Bacon Burger</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-burger.jpg"/>
|
||||
</record>
|
||||
@@ -76,7 +75,7 @@
|
||||
<field name="list_price">7.0</field>
|
||||
<field name="name">Cheese Burger</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-cheeseburger.jpg"/>
|
||||
</record>
|
||||
@@ -85,7 +84,7 @@
|
||||
<field name="list_price">3.0</field>
|
||||
<field name="name">Chicken Curry Sandwich</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-sandwich.jpg"/>
|
||||
</record>
|
||||
@@ -94,7 +93,7 @@
|
||||
<field name="list_price">3.0</field>
|
||||
<field name="name">Spicy Tuna Sandwich</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-tuna.jpg"/>
|
||||
</record>
|
||||
@@ -103,7 +102,7 @@
|
||||
<field name="list_price">3.9</field>
|
||||
<field name="name">Mozzarella Sandwich</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-mozza.jpg"/>
|
||||
</record>
|
||||
@@ -112,7 +111,7 @@
|
||||
<field name="list_price">3.4</field>
|
||||
<field name="name">Club Sandwich</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-club.jpg"/>
|
||||
</record>
|
||||
@@ -121,7 +120,7 @@
|
||||
<field name="list_price">12.0</field>
|
||||
<field name="name">Lunch Maki 18pc</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-maki.jpg"/>
|
||||
</record>
|
||||
@@ -130,7 +129,7 @@
|
||||
<field name="list_price">13.80</field>
|
||||
<field name="name">Lunch Salmon 20pc</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-salmon.jpg"/>
|
||||
</record>
|
||||
@@ -139,7 +138,7 @@
|
||||
<field name="list_price">14.0</field>
|
||||
<field name="name">Lunch Temaki mix 3pc</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-temaki.jpg"/>
|
||||
</record>
|
||||
@@ -148,7 +147,7 @@
|
||||
<field name="list_price">9.25</field>
|
||||
<field name="name">Salmon and Avocado</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="food"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('food')])]"/>
|
||||
<field name="categ_id" ref="pos_restaurant.product_category_pos_food"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-salmon-avocado.jpg"/>
|
||||
</record>
|
||||
@@ -159,7 +158,7 @@
|
||||
<field name="list_price">2.20</field>
|
||||
<field name="name">Coca-Cola</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="drinks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('drinks')])]"/>
|
||||
<field name="categ_id" ref="point_of_sale.product_category_pos"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-coke.jpg"/>
|
||||
</record>
|
||||
@@ -169,7 +168,7 @@
|
||||
<field name="list_price">2.20</field>
|
||||
<field name="name">Water</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="drinks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('drinks')])]"/>
|
||||
<field name="categ_id" ref="point_of_sale.product_category_pos"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-water.jpg"/>
|
||||
</record>
|
||||
@@ -179,7 +178,7 @@
|
||||
<field name="list_price">2.20</field>
|
||||
<field name="name">Minute Maid</field>
|
||||
<field name="weight">0.01</field>
|
||||
<field name="pos_categ_id" ref="drinks"/>
|
||||
<field name="pos_categ_ids" eval="[(6, 0, [ref('drinks')])]"/>
|
||||
<field name="categ_id" ref="point_of_sale.product_category_pos"/>
|
||||
<field name="image_1920" type="base64" file="pos_restaurant/static/img/th-minute_maid.jpg"/>
|
||||
</record>
|
||||
@@ -504,5 +503,5 @@
|
||||
<field name="position_v">315</field>
|
||||
</record>
|
||||
|
||||
<function model="pos.config" name="add_cash_payment_method" />
|
||||
</odoo>
|
||||
<function model="pos.config" name="add_cash_payment_method"/>
|
||||
</odoo>
|
||||
@@ -8,9 +8,7 @@ import { nbsp } from "@web/core/utils/strings";
|
||||
|
||||
patch(ActionpadWidget.prototype, "point_of_sale.ActionpadWidget", {
|
||||
get swapButton() {
|
||||
return (
|
||||
this.props.actionType === "payment" && this.pos.config.module_pos_restaurant
|
||||
);
|
||||
return this.props.actionType === "payment" && this.pos.config.module_pos_restaurant;
|
||||
},
|
||||
get currentOrder() {
|
||||
return this.pos.get_order();
|
||||
@@ -57,8 +55,8 @@ patch(ActionpadWidget.prototype, "point_of_sale.ActionpadWidget", {
|
||||
const orderChange = this.currentOrder.getOrderChanges().orderlines;
|
||||
for (const idx in orderChange) {
|
||||
const orderline = orderChange[idx];
|
||||
const category = this.pos.db.get_product_by_id(orderline.product_id)
|
||||
.pos_categ_id[1];
|
||||
const categoryId = this.pos.db.get_product_by_id(orderline.product_id).pos_categ_ids[0];
|
||||
const category = this.pos.db.category_by_id[categoryId].name;
|
||||
const numProd = orderline.quantity;
|
||||
categories[category] = categories[category] ? categories[category] + numProd : numProd;
|
||||
}
|
||||
|
||||
@@ -39,13 +39,6 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'journal_id': second_cash_journal.id,
|
||||
})
|
||||
|
||||
printer = self.env['pos.printer'].create({
|
||||
'name': 'Preparation Printer',
|
||||
'epson_printer_ip': '127.0.0.1',
|
||||
'printer_type': 'epson_epos',
|
||||
'product_categories_ids': [drinks_category.id]
|
||||
})
|
||||
|
||||
pos_config = self.env['pos.config'].create({
|
||||
'name': 'Bar',
|
||||
'module_pos_restaurant': True,
|
||||
@@ -144,7 +137,7 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'list_price': 2.20,
|
||||
'name': 'Coca-Cola',
|
||||
'weight': 0.01,
|
||||
'pos_categ_id': drinks_category.id,
|
||||
'pos_categ_ids': [(4, drinks_category.id)],
|
||||
'categ_id': self.env.ref('point_of_sale.product_category_pos').id,
|
||||
'taxes_id': [(6, 0, [])],
|
||||
})
|
||||
@@ -154,7 +147,7 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'list_price': 2.20,
|
||||
'name': 'Water',
|
||||
'weight': 0.01,
|
||||
'pos_categ_id': drinks_category.id,
|
||||
'pos_categ_ids': [(4, drinks_category.id)],
|
||||
'categ_id': self.env.ref('point_of_sale.product_category_pos').id,
|
||||
'taxes_id': [(6, 0, [])],
|
||||
})
|
||||
@@ -164,7 +157,7 @@ class TestFrontend(odoo.tests.HttpCase):
|
||||
'list_price': 2.20,
|
||||
'name': 'Minute Maid',
|
||||
'weight': 0.01,
|
||||
'pos_categ_id': drinks_category.id,
|
||||
'pos_categ_ids': [(4, drinks_category.id)],
|
||||
'categ_id': self.env.ref('point_of_sale.product_category_pos').id,
|
||||
'taxes_id': [(6, 0, [])],
|
||||
})
|
||||
|
||||
@@ -153,11 +153,10 @@ class PosConfig(models.Model):
|
||||
*(
|
||||
self.limit_categories
|
||||
and self.iface_available_categ_ids
|
||||
and [("pos_categ_id", "in", self.iface_available_categ_ids.ids)]
|
||||
and [("pos_categ_ids", "in", self.iface_available_categ_ids.ids)]
|
||||
or []
|
||||
),
|
||||
],
|
||||
order="pos_categ_id.sequence asc nulls last",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ class ProductProduct(models.Model):
|
||||
"name": product._get_name(),
|
||||
"product_id": product.id,
|
||||
"description_sale": product.description_sale,
|
||||
"tag": product.pos_categ_id.name if product.pos_categ_id else "Other",
|
||||
"tags": product.pos_categ_ids.mapped("name") or ["Other"],
|
||||
"is_pos_groupable": product.uom_id.is_pos_groupable,
|
||||
}
|
||||
for product in self
|
||||
|
||||
@@ -10,7 +10,7 @@ export class Product extends Reactive {
|
||||
name,
|
||||
product_id,
|
||||
description_sale,
|
||||
tag,
|
||||
tags,
|
||||
is_pos_groupable,
|
||||
},
|
||||
selfOrder
|
||||
@@ -27,7 +27,7 @@ export class Product extends Reactive {
|
||||
this.attributes = product.attributes;
|
||||
this.name = product.name;
|
||||
this.description_sale = product.description_sale;
|
||||
this.tag = product.tag;
|
||||
this.tags = product.tags;
|
||||
this.is_pos_groupable = product.is_pos_groupable;
|
||||
|
||||
// data
|
||||
|
||||
@@ -50,7 +50,7 @@ export class SelfOrder {
|
||||
this.products = this.products.map((p) => {
|
||||
const product = new Product(p, this);
|
||||
|
||||
this.tagList.add(product.tag);
|
||||
this.tagList.add(...product.tags);
|
||||
this.productByIds[product.id] = product;
|
||||
|
||||
return product;
|
||||
@@ -67,7 +67,13 @@ export class SelfOrder {
|
||||
);
|
||||
}
|
||||
|
||||
this.productsGroupedByTag = groupBy(this.products, "tag");
|
||||
this.productsGroupedByTag = this._getProductsGroupedByTag(this.products);
|
||||
}
|
||||
_getProductsGroupedByTag(products) {
|
||||
const productsDuplicatedSuchThatEachHasOneTag = products.flatMap((product) =>
|
||||
product.tags.map((tag) => ({ ...product, tag }))
|
||||
);
|
||||
return groupBy(productsDuplicatedSuchThatEachHasOneTag, "tag");
|
||||
}
|
||||
|
||||
saveOrderToLocalStorage(orders) {
|
||||
|
||||
Reference in New Issue
Block a user