17 changed files with 559 additions and 0 deletions
@ -0,0 +1,39 @@ |
|||
======================== |
|||
POS Product Multiple UOM |
|||
======================== |
|||
|
|||
Added option to update the uom of products in pos. |
|||
|
|||
Installation |
|||
============ |
|||
|
|||
Just select it from available modules to install it, there is no need to extra installations. |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
After installation, go to Inventory -> Settings |
|||
and enable the multiple uom option under the 'Products' section. |
|||
|
|||
Known issues / Roadmap |
|||
====================== |
|||
|
|||
* ... |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Contact odoo@cybrosys.com |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Linto CT <linto@cybrosys.in> |
|||
* Shereef PT <shereef@cybrosys.in> |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit https://www.cybrosys.com. |
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: LINTO C T(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
|
|||
import models |
@ -0,0 +1,45 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2018-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: LINTO C T(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
{ |
|||
'name': 'POS Product Multiple UOM', |
|||
'version': '10.0.1.0.0', |
|||
'category': 'Point of Sale', |
|||
'summary': 'Multiple UOM for Products', |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'depends': ['point_of_sale', 'stock'], |
|||
'data': [ |
|||
'views/pos_template.xml', |
|||
'views/pos_view_extended.xml', |
|||
], |
|||
'demo': [], |
|||
'qweb': ['static/src/xml/pos.xml'], |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'LGPL-3', |
|||
'installable': True, |
|||
'application': False, |
|||
'auto_install': False, |
|||
} |
@ -0,0 +1,3 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import pos_orderline |
@ -0,0 +1,112 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from odoo import _ |
|||
from odoo.tools import float_is_zero |
|||
from odoo import models, fields, api |
|||
|
|||
|
|||
class PosOrderLinesExtended(models.Model): |
|||
_inherit = 'pos.order.line' |
|||
|
|||
uom_id = fields.Many2one('product.uom', string="UOM") |
|||
|
|||
@api.model |
|||
def create(self, values): |
|||
"""updating uom to orderlines""" |
|||
try: |
|||
if values.get('uom_id'): |
|||
values['uom_id'] = values['uom_id'][0] |
|||
except Exception: |
|||
values['uom_id'] = None |
|||
pass |
|||
res = super(PosOrderLinesExtended, self).create(values) |
|||
return res |
|||
|
|||
|
|||
class PosOrderExtended(models.Model): |
|||
_inherit = 'pos.order' |
|||
|
|||
# overwriting this function because, we need to set the uom id based on the unit |
|||
# in the orderline instead of product uom, at the time of creating the stock moves |
|||
def create_picking(self): |
|||
"""Create a picking for each order and validate it.""" |
|||
Picking = self.env['stock.picking'] |
|||
Move = self.env['stock.move'] |
|||
StockWarehouse = self.env['stock.warehouse'] |
|||
for order in self: |
|||
if not order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu']): |
|||
continue |
|||
address = order.partner_id.address_get(['delivery']) or {} |
|||
picking_type = order.picking_type_id |
|||
return_pick_type = order.picking_type_id.return_picking_type_id or order.picking_type_id |
|||
order_picking = Picking |
|||
return_picking = Picking |
|||
moves = Move |
|||
location_id = order.location_id.id |
|||
if order.partner_id: |
|||
destination_id = order.partner_id.property_stock_customer.id |
|||
else: |
|||
if (not picking_type) or (not picking_type.default_location_dest_id): |
|||
customerloc, supplierloc = StockWarehouse._get_partner_locations() |
|||
destination_id = customerloc.id |
|||
else: |
|||
destination_id = picking_type.default_location_dest_id.id |
|||
|
|||
if picking_type: |
|||
message = _("This transfer has been created from the point of sale session: <a href=# data-oe-model=pos.order data-oe-id=%d>%s</a>") % (order.id, order.name) |
|||
picking_vals = { |
|||
'origin': order.name, |
|||
'partner_id': address.get('delivery', False), |
|||
'date_done': order.date_order, |
|||
'picking_type_id': picking_type.id, |
|||
'company_id': order.company_id.id, |
|||
'move_type': 'direct', |
|||
'note': order.note or "", |
|||
'location_id': location_id, |
|||
'location_dest_id': destination_id, |
|||
} |
|||
pos_qty = any([x.qty > 0 for x in order.lines if x.product_id.type in ['product', 'consu']]) |
|||
if pos_qty: |
|||
order_picking = Picking.create(picking_vals.copy()) |
|||
order_picking.message_post(body=message) |
|||
neg_qty = any([x.qty < 0 for x in order.lines if x.product_id.type in ['product', 'consu']]) |
|||
if neg_qty: |
|||
return_vals = picking_vals.copy() |
|||
return_vals.update({ |
|||
'location_id': destination_id, |
|||
'location_dest_id': return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id, |
|||
'picking_type_id': return_pick_type.id |
|||
}) |
|||
return_picking = Picking.create(return_vals) |
|||
return_picking.message_post(body=message) |
|||
|
|||
for line in order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not float_is_zero(l.qty, precision_rounding=l.product_id.uom_id.rounding)): |
|||
moves |= Move.create({ |
|||
'name': line.name, |
|||
'product_uom': line.uom_id.id, |
|||
'picking_id': order_picking.id if line.qty >= 0 else return_picking.id, |
|||
'picking_type_id': picking_type.id if line.qty >= 0 else return_pick_type.id, |
|||
'product_id': line.product_id.id, |
|||
'product_uom_qty': abs(line.qty), |
|||
'state': 'draft', |
|||
'location_id': location_id if line.qty >= 0 else destination_id, |
|||
'location_dest_id': destination_id if line.qty >= 0 else return_pick_type != picking_type and return_pick_type.default_location_dest_id.id or location_id, |
|||
}) |
|||
# prefer associating the regular order picking, not the return |
|||
order.write({'picking_id': order_picking.id or return_picking.id}) |
|||
|
|||
if return_picking: |
|||
order._force_picking_done(return_picking) |
|||
if order_picking: |
|||
order._force_picking_done(order_picking) |
|||
|
|||
# when the pos.config has no picking_type_id set only the moves will be created |
|||
if moves and not return_picking and not order_picking: |
|||
tracked_moves = moves.filtered(lambda move: move.product_id.tracking != 'none') |
|||
untracked_moves = moves - tracked_moves |
|||
tracked_moves.action_confirm() |
|||
untracked_moves.action_assign() |
|||
moves.filtered(lambda m: m.state in ['confirmed', 'waiting']).force_assign() |
|||
moves.filtered(lambda m: m.product_id.tracking == 'none').action_done() |
|||
|
|||
return True |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 50 KiB |
@ -0,0 +1,92 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h2 class="oe_slogan">POS Product Multiple UOM</h2> |
|||
<h3 class="oe_slogan"></h3> |
|||
<h4 class="oe_slogan"><a href="https://www.cybrosys.com">Cybrosys Technologies</a> </h4> |
|||
</div> |
|||
<div class="oe_row oe_spaced" style="padding-left:65px;"> |
|||
<h3><p style="margin-left: 42px;"><b>Features:</b></p></h3> |
|||
<div> |
|||
<span style="color:green;"> ☑ </span> Multiple UOM for products in POS.<br/> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_picture"> |
|||
<h3 class="oe_slogan">Overview</h3> |
|||
<p class="oe_mt32 text-justify" style="text-align: center;"> |
|||
By default, Odoo does not provide the option to update the unit of measure |
|||
of the products we select in the point of sale. We can sell products only in its |
|||
default unit. This module provides an option to update the UOM of the products |
|||
in point of sale. The stock will also be updated in the new UOM. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h5 class="oe_slogan"><b>New button added for opening the wizard.</b></h5> |
|||
<div style="text-align:center;"> |
|||
<div class="oe_demo oe_picture oe_screenshot"> |
|||
<img src="modify_uom_button.png"> |
|||
</div> |
|||
</div> |
|||
<br /> |
|||
<div class="oe_row oe_spaced"> |
|||
<h5 class="oe_slogan"><b>This button will open a wizard which will show all the UOMs |
|||
associated with the selected product. |
|||
</b></h5> |
|||
</div> |
|||
<div class="col-md-12"> |
|||
<div class="oe_row_img oe_demo oe_picture oe_screenshot"> |
|||
<img src="multi_uom_wiz.png"> |
|||
</div> |
|||
</div> |
|||
<div class="oe_row oe_spaced"> |
|||
<p class="oe_slogan"> |
|||
We can select the UOMs available for this product and update it. |
|||
</p> |
|||
</div> |
|||
|
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="col-md-12"> |
|||
<div class=" oe_demo oe_picture oe_screenshot"> |
|||
<img src="orderlines.png" /> |
|||
<div class="oe_demo_footer oe_centeralign" style="background-color:rgba(162, 70, 137, 0.7);"> |
|||
Updated orderline |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|||
<div> |
|||
<a class="btn btn-primary btn-lg mt8" |
|||
style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i |
|||
class="fa fa-envelope"></i> Email </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/contact/"><i |
|||
class="fa fa-phone"></i> Contact Us </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/odoo-customization-and-installation/"><i |
|||
class="fa fa-check-square"></i> Request Customization </a> |
|||
</div> |
|||
<br> |
|||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|||
<div> |
|||
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
|||
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
|||
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
|||
</div> |
|||
</div> |
|||
</section> |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 130 KiB |
@ -0,0 +1,22 @@ |
|||
.button-multi-uom{ |
|||
width: 100%; |
|||
height: 32px; |
|||
font-size: 16px; |
|||
text-align: center; |
|||
border-radius: 5px; |
|||
} |
|||
.multi-uom-span { |
|||
width: 50%; |
|||
border: 1px solid; |
|||
/* vertical-align: middle; */ |
|||
align-self: center; |
|||
padding: 5px 10px; |
|||
background-color: #6EC89B; |
|||
color: #fff; |
|||
LINE-HEIGHT: 2.5; |
|||
transition: all 150ms linear; |
|||
} |
|||
|
|||
.popup-product-creation{ |
|||
height: 50% !important; |
|||
} |
After Width: | Height: | Size: 36 KiB |
@ -0,0 +1,152 @@ |
|||
odoo.define('product_multi_uom_pos.multi_uom',function(require) { |
|||
"use strict"; |
|||
|
|||
var gui = require('point_of_sale.gui'); |
|||
var PosBaseWidget = require('point_of_sale.BaseWidget'); |
|||
var core = require('web.core'); |
|||
var models = require('point_of_sale.models'); |
|||
var OrderlineSuper = models.Orderline; |
|||
var pos_screens = require('point_of_sale.screens'); |
|||
|
|||
var MultiUomWidget = PosBaseWidget.extend({ |
|||
template: 'MultiUomWidget', |
|||
init: function(parent, args) { |
|||
this._super(parent, args); |
|||
this.options = {}; |
|||
this.uom_list = []; |
|||
}, |
|||
events: { |
|||
'click .button.cancel': 'click_cancel', |
|||
'click .button.confirm': 'click_confirm', |
|||
}, |
|||
/*function returns all the uom s in the specified category*/ |
|||
get_units_by_category: function(uom_list, categ_id){ |
|||
var uom_by_categ = [] |
|||
for (var uom in uom_list){ |
|||
if(uom_list[uom].category_id[0] == categ_id[0]){ |
|||
uom_by_categ.push(uom_list[uom]); |
|||
} |
|||
} |
|||
return uom_by_categ; |
|||
}, |
|||
/*Find the base price(price of the product for reference unit)*/ |
|||
find_reference_unit_price: function(product, product_uom){ |
|||
if(product_uom.uom_type == 'reference'){ |
|||
return product.price; |
|||
} |
|||
else if(product_uom.uom_type == 'smaller'){ |
|||
return (product.price * product_uom.factor); |
|||
} |
|||
else if(product_uom.uom_type == 'bigger'){ |
|||
return (product.price / product_uom.factor_inv); |
|||
} |
|||
}, |
|||
/*finds the latest price for the product based on the new uom selected*/ |
|||
get_latest_price: function(uom, product){ |
|||
var uom_by_category = this.get_units_by_category(this.pos.units_by_id, uom.category_id); |
|||
var product_uom = this.pos.units_by_id[product.uom_id[0]]; |
|||
var ref_price = this.find_reference_unit_price(product, product_uom); |
|||
var ref_unit = null; |
|||
for (var i in uom_by_category){ |
|||
if(uom_by_category[i].uom_type == 'reference'){ |
|||
ref_unit = uom_by_category[i]; |
|||
break; |
|||
} |
|||
} |
|||
if(ref_unit){ |
|||
if(uom.uom_type == 'bigger'){ |
|||
return (ref_price * uom.factor_inv); |
|||
} |
|||
else if(uom.uom_type == 'smaller'){ |
|||
return (ref_price / uom.factor); |
|||
} |
|||
else if(uom.uom_type == 'reference'){ |
|||
return ref_price; |
|||
} |
|||
} |
|||
return product.price; |
|||
}, |
|||
/*Rendering the wizard*/ |
|||
show: function(options){ |
|||
options = options || {}; |
|||
var current_uom = this.pos.units_by_id[options.uom_list[0]]; |
|||
var uom_list = this.pos.units_by_id; |
|||
var uom_by_category = this.get_units_by_category(uom_list, current_uom.category_id); |
|||
this.uom_list = uom_by_category; |
|||
this.current_uom = options.uom_list[0]; |
|||
this.renderElement(); |
|||
}, |
|||
close: function(){ |
|||
if (this.pos.barcode_reader) { |
|||
this.pos.barcode_reader.restore_callbacks(); |
|||
} |
|||
}, |
|||
click_confirm: function(){ |
|||
var self = this; |
|||
var uom = parseInt(this.$('.uom').val()); |
|||
var order = self.pos.get_order(); |
|||
var orderline = order.get_selected_orderline(); |
|||
var selected_uom = this.pos.units_by_id[uom]; |
|||
orderline.uom_id = []; |
|||
orderline.uom_id[0] = uom; |
|||
orderline.uom_id[1] = selected_uom.display_name; |
|||
|
|||
/*Updating the orderlines*/ |
|||
order.remove_orderline(orderline); |
|||
order.add_orderline(orderline); |
|||
var latest_price = this.get_latest_price(selected_uom, orderline.product); |
|||
order.get_selected_orderline().set_unit_price(latest_price); |
|||
this.gui.close_popup(); |
|||
return; |
|||
|
|||
}, |
|||
click_cancel: function(){ |
|||
this.gui.close_popup(); |
|||
}, |
|||
}); |
|||
gui.define_popup({name:'multi_uom_screen', widget: MultiUomWidget}); |
|||
|
|||
models.Orderline = models.Orderline.extend({ |
|||
/*Adding uom_id to orderline*/ |
|||
initialize: function(attr,options){ |
|||
OrderlineSuper.prototype.initialize.call(this, attr, options); |
|||
this.uom_id = this ? this.product.uom_id: []; |
|||
}, |
|||
export_as_JSON: function() { |
|||
var result = OrderlineSuper.prototype.export_as_JSON.call(this); |
|||
result.uom_id = this.uom_id; |
|||
return result; |
|||
}, |
|||
/*this function now will return the uom_id of the orderline , |
|||
instead of the default uom_id of the product*/ |
|||
get_unit: function(){ |
|||
var res = OrderlineSuper.prototype.get_unit.call(this); |
|||
|
|||
var unit_id = this.uom_id; |
|||
if(!unit_id){ |
|||
return res; |
|||
} |
|||
unit_id = unit_id[0]; |
|||
if(!this.pos){ |
|||
return undefined; |
|||
} |
|||
return this.pos.units_by_id[unit_id]; |
|||
} |
|||
}); |
|||
|
|||
pos_screens.ActionpadWidget.include({ |
|||
/*opening the wizard on button click*/ |
|||
renderElement: function() { |
|||
this._super(); |
|||
var self = this; |
|||
this.$('.multi-uom-span').click(function(){ |
|||
var orderline = self.pos.get_order().get_selected_orderline(); |
|||
var options = { |
|||
'uom_list': orderline.product.uom_id |
|||
}; |
|||
self.gui.show_popup('multi_uom_screen', options); |
|||
}); |
|||
} |
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,39 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates id="template" xml:space="preserve"> |
|||
<t t-extend="ActionpadWidget"> |
|||
<t t-jquery="div.actionpad" t-operation="before"> |
|||
<div class="button-multi-uom"> |
|||
<span class="multi-uom-span"> |
|||
Modify Unit of Measure |
|||
</span> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
|
|||
<t t-name="MultiUomWidget"> |
|||
<div class="modal-dialog multi-uom"> |
|||
<div class="popup popup-product-creation"> |
|||
<p class="title">Select Unit of Measure</p> |
|||
<div> |
|||
<select class="uom" style="width:35%;height:30px;border-radius:5px;"> |
|||
<t t-foreach='widget.uom_list' t-as='uom'> |
|||
<option t-att-value='uom.id' |
|||
t-att-selected="((uom.id == widget.current_uom) ? true:undefined)" > |
|||
<t t-esc='uom.display_name'/> |
|||
</option> |
|||
</t> |
|||
</select> |
|||
</div> |
|||
<div class="footer"> |
|||
<div class="button confirm"> |
|||
Ok |
|||
</div> |
|||
<div class="button cancel"> |
|||
Cancel |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
|
|||
</templates> |
@ -0,0 +1,14 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data> |
|||
<template id="assets" inherit_id="point_of_sale.assets"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/product_multi_uom_pos/static/src/js/multi_uom.js"></script> |
|||
</xpath> |
|||
<xpath expr="//link[@id='pos-stylesheet']" position="after"> |
|||
<link rel="stylesheet" href="/product_multi_uom_pos/static/src/css/style.css"/> |
|||
</xpath> |
|||
</template> |
|||
|
|||
</data> |
|||
</odoo> |
@ -0,0 +1,16 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<data> |
|||
<!--Adding uom id to lines--> |
|||
<record id="pos_order_line_uom" model="ir.ui.view"> |
|||
<field name="name">UOM for Order-line</field> |
|||
<field name="model">pos.order</field> |
|||
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form" /> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='lines']/tree/field[@name='qty']" position="after"> |
|||
<field name="uom_id"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
Loading…
Reference in new issue