-
-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[16.0] pos_self_service_* #1157
base: 16.0
Are you sure you want to change the base?
Conversation
Pinging @huguesdk for an early eye-over of the code to see if it passes the sniff test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for this! it seems like a strong base. some things i noticed while testing it:
when it is not able to connect to the iotbox, a red dialog box appears saying:
Unknown Error
Unable to show information about this error.
a new one appears on top of the previous one every few seconds. it would be nice to have a more informative message (or an icon somewhere showing the status).
moreover, it doesn’t seem to take the status of the scale into account: even if it is reported as disconnected, it will read the weight repeatedly.
with this module loaded, the normal (not self-service weight) point of sale interface is different (while it shouldn’t): to purple odoo top bar is not visible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea to mention “weight” in the module name. it seems that i forgot about that. 👍
class PosConfig(models.Model): | ||
_inherit = "pos.config" | ||
|
||
iface_self_service = fields.Boolean( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i’m wondering about iface
in the name. i see other settings like that in odoo, but they all seem directly related to hardware devices. what do you think about is_self_service_weight
or enable_self_service_weight
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 4d2c034
string="Is Self-Service", | ||
help="Use this POS as self-service point", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think mentioning “weight” would be useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 4d2c034
class ResConfigSettings(models.TransientModel): | ||
_inherit = "res.config.settings" | ||
|
||
pos_iface_self_service = fields.Boolean( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here: what about pos_is_self_service_weight
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 4d2c034
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where are all these css rules coming from? is that self-made or copied from somewhere else?
const Chrome = require("point_of_sale.Chrome"); | ||
const Registries = require("point_of_sale.Registries"); | ||
|
||
const SelfServiceChrome = (Chrome_) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason for the underscore in Chrome_
? i know it is a local variable independent of the one defined above, but i see that most oca modules use the same name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like Carmen's way better but I changed it anyway for consistency.
cf 4d2c034
|
||
const {onMounted, onWillUnmount, useState} = owl; | ||
|
||
class WeightWidget extends PosComponent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could this inherit from point_of_sale.ScaleScreen
to avoid re-implementing similar methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's a good idea :
- the template displays the order button : should be hidden in both tare and product mode
- the template displays the price, it should be hidden in tare mode
- it needs to be loaded with a product
- it is usually called as a popup which returns a payload
If there is a clean way to do it, please point in the right direction :-)
const Registries = require("point_of_sale.Registries"); | ||
const {useListener} = require("@web/core/utils/hooks"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@huguesdk i don't understand the difference between these two syntaxes, can you enlighten me ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the second syntax is called destructuring assignment and in this case it is equivalent to:
const useListener = require("@web/core/utils/hooks").useListener;
it avoids repeating the variable name, but it is even more useful when assigning multiple variables together, like this:
const {useListener, useService} = require("@web/core/utils/hooks");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks !
_readScale() { | ||
this.env.proxy_queue.schedule(this._setWeight.bind(this), { | ||
duration: 500, | ||
repeat: true, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand correctly ? Once the weight widget is mounted, _read_scale
schedules a call of _set_weight
every 500ms ?
I do not understand the bind
instruction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unlike in python, in javascript a reference to a method is not bound to a this
variable. bind()
returns a new function that, when called, provides the this
variable to the method. more information on mdn.
i’m not familiar with the schedule()
function, but as i understand it, it will call this._setWeight()
every 500 ms, forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks !
@huguesdk should i consider translating the code as a Native JS Module ? |
4ce441e
to
90a8935
Compare
squashed previous work |
574f882
to
9c19367
Compare
fd7eaec
to
b070c43
Compare
b070c43
to
cfb0155
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robinkeunen thanks for all the improvements!
some remarks:
- the red “unknown error” dialog box still appears.
- the top bar is now visible again in the normal pos, but in self-service weighing mode as well, while it should be hidden, as the customer shouldn’t be able to easily exit the interface.
- previously, the module was called
pos_self_service_base
, without a reference to weighing, while here it is specifically about weighing, so i suggest to rename all classes (and files) from*SelfService*
to*SelfServiceWeighing*
. - (not that important) it is possible to create a self-service weight station without checking the “electronic scale” checkbox is the iot box section. having something checking this would be a plus (only if it is quick and easy).
} | ||
|
||
.foodbox { | ||
background-image: url("../../img/empty_foodbox_on_scale.svg"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is this file?
is all this css needed at this point or is this mostly coming from the old pos_self_service_base
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not look into it at all. Writing it down for later.
@@ -0,0 +1,35 @@ | |||
/** @odoo-module alias=pos_self_service_weight_base.Chrome **/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the alias needed? (same remark for all modules)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is needed if we want to allow other modules to inherit this one using the old Odoo define syntax. so not strictly needed.
i also prefer importing module names than file names but that's maybe me coming from python and lack consistency.
do you think I should change it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this module is extending classes that still use the old define
syntax, i think t makes sense to keep it.
} | ||
|
||
showTicketButton() { | ||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a why comment would help to understand what this method is for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
_inherit = "pos.config" | ||
|
||
is_self_service_weight_point = fields.Boolean( | ||
string="Is Self-Service", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
string="Is Self-Service", | |
string="Is a Self-Service Weighing Station", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<div class="o_setting_right_pane"> | ||
<label for="is_self_service_weight_point" /> | ||
<div class="text-muted mb16" id="is_self_service_weight_point_text"> | ||
Use your PoS as self-service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use your PoS as self-service | |
Use this PoS as a self-service weighing station |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
--> | ||
<templates id="template" xml:space="preserve"> | ||
|
||
<t t-name="pos_self_service_weight_base.SelfServiceControlButton" owl="1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<t t-name="pos_self_service_weight_base.SelfServiceControlButton" owl="1"> | |
<t t-name="pos_self_service_weight_base.SelfServiceWeighingControlButton" owl="1"> |
--> | ||
<templates id="template" xml:space="preserve"> | ||
|
||
<t t-name="pos_self_service_weight_base.AbstractSelfServiceScreen" owl="1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<t t-name="pos_self_service_weight_base.AbstractSelfServiceScreen" owl="1"> | |
<t t-name="pos_self_service_weight_base.AbstractSelfServiceWeighingScreen" owl="1"> |
--> | ||
<templates id="template" xml:space="preserve"> | ||
|
||
<t t-name="pos_self_service_weight_base.SelfServiceActionButton" owl="1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<t t-name="pos_self_service_weight_base.SelfServiceActionButton" owl="1"> | |
<t t-name="pos_self_service_weight_base.SelfServiceWeighingActionButton" owl="1"> |
SPDX-License-Identifier: AGPL-3.0-or-later | ||
--> | ||
<templates id="template" xml:space="preserve"> | ||
<t t-name="pos_self_service_weight_base.SelfServiceWelcomeScreen" owl="1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<t t-name="pos_self_service_weight_base.SelfServiceWelcomeScreen" owl="1"> | |
<t t-name="pos_self_service_weight_base.SelfServiceWeighingWelcomeScreen" owl="1"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done for all
<div class="screen"> | ||
<div class="screen-full-width"> | ||
<div class="self-service-action-buttons"> | ||
<SelfServiceActionButton t-if="env.isDebug()" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this button shown only in debug mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It exists to test the behavior of the base module when there are nos other modules installed. It can be removed in the future.
cfb0155
to
ad88585
Compare
@huguesdk I restored the top bar because
To mitigate the risk of closing the point of sale by accident, I added the confirmation popup (suggestion from Rémy). I tend to agree that the risk to have customer closing the weighing station is high so, keeping in mind the add benefits of the bar, do you agree to rather hide the "close" button and remove the popup altogether. |
Signed-off-by: Carmen Bianca BAKKER <carmen@coopiteasy.be> [IMP] pos_self_service_weight: hide orders button [IMP] pos_self_service: add CloseSelfServicePopup No cash is manipulated in self service mode do not therefore ask the user to control the amounts. [IMP] pos_self_service: translate to js native modules [IMP] pos_self_service: rename files to .esm.js [IMP] pos_self_service: rename files to .esm.js [ADD] pos_self_service: add welcome screen [REF] pos_self_service: rename SSScreen
ad88585
to
636b82f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a big review. Some of the things in the review are my own bad/questionable decisions.
@@ -0,0 +1,3 @@ | |||
* `Coop IT Easy SC, Odoo Community Association (OCA) <https://github.com/OCA/pos>`_: | |||
|
|||
* Carmen Bianca BAKKER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add Robin Keunen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<attribute name="t-if">showTicketButton()</attribute> | ||
</xpath> | ||
</t> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There used to be this code here:
<xpath expr="//div[hasclass('pos-topheader')]" position="attributes">
<attribute
name="t-att-class"
>{ oe_hidden: state.uiState !== 'READY' || env.pos.config.iface_self_service }</attribute>
</xpath>
<xpath expr="//div[hasclass('pos-content')]" position="attributes">
<t t-if="env.pos.config.ifaceself_service">
<attribute name="class">pos-content positionzero</attribute>
</t>
</xpath>
This removed the bar at the top. Now, a user can click on 'close', and be sent back to the Odoo interface. This is bad for two reasons:
- Depending on how Odoo is configured, this allows the user access to things they shouldn't be able to see.
- It may be difficult/time-consuming to recover from such an error.
'Close' is also an incredibly normal button to press, so this may be very frequent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I talked with @robinkeunen after forgetting to read his comment from earlier today → hiding the close button would also be a satisfactory solution. This would also allow getting rid of some code elsewhere related to the close pop-up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
const SelfServiceWeighingHeaderButton = (HeaderButton) => | ||
class extends HeaderButton { | ||
async onClick() { | ||
if (!this.env.pos.config.is_self_service_weighing_point) { | ||
return super.onClick(); | ||
} | ||
try { | ||
const info = await this.env.pos.getClosePosInfo(); | ||
this.showPopup("CloseSelfServiceWeighingPopup", { | ||
info: info, | ||
keepBehind: true, | ||
}); | ||
} catch (e) { | ||
if (isConnectionError(e)) { | ||
this.showPopup("OfflineErrorPopup", { | ||
title: this.env._t("Network Error"), | ||
body: this.env._t( | ||
"Please check your internet connection and try again." | ||
), | ||
}); | ||
} else { | ||
this.showPopup("ErrorPopup", { | ||
title: this.env._t("Unknown Error"), | ||
body: this.env._t( | ||
"An unknown error prevents us from getting closing information." | ||
), | ||
}); | ||
} | ||
} | ||
} | ||
}; | ||
Registries.Component.extend(HeaderButton, SelfServiceWeighingHeaderButton); | ||
export default SelfServiceWeighingHeaderButton; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof… This is 99% upstream code, except uses a custom implementation of the closing pop-up. That isn't great. Can we not edit the XML/template of ClosePosPopup
to display something completely different if the POS is a weighing station?
Although, as mentioned in a previous comment, I'm not sure we should be able to close from this screen.
...base/static/src/js/Screens/SelfServiceWeighingScreen/SelfServiceWeighingControlButton.esm.js
Outdated
Show resolved
Hide resolved
class SelfServiceWeighingActionButton extends PosComponent { | ||
get name() { | ||
return "Base Action"; | ||
} | ||
|
||
get faSymbol() { | ||
return "fa-barcode"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this class? This seems very similar to SelfServiceWeighingControlButton
, but with some strange defaults?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I've worked this out. It's the button on the welcome screen. The defaults are there because there's a button in the debug mode?
I think a few things need to happen to improve this:
- Rename
SelfServiceWeighingActionButton
toSelfServiceWeighingWelcomeButton
. This is much easier to disambiguate fromSelfServiceWeighingControlButton
. - Remove all the default values from
SelfServiceWeighingWelcomeButton
. - Create
SelfServiceWeighingDebugButton
with the removed defaults.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<templates id="template" xml:space="preserve"> | ||
|
||
<t | ||
t-name="pos_self_service_weighing_base.AbstractSelfServiceWeighingScreen" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name does not match file name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<t t-name="pos_self_service_weighing_tare.SelfServiceWeighingTareScreen" owl="1"> | ||
<div class="screen"> | ||
<div class="screen-full-width"> | ||
<div class="leftpane pane-border"> | ||
<WeightWidget /> | ||
<div class="self-service-control-buttons"> | ||
<SelfServiceWeighingHomeButton /> | ||
</div> | ||
</div> | ||
<div class="rightpane"> | ||
<div class="self-service-action-buttons"> | ||
<SelfServiceWeighingPrintTareButton /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</t> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This completely re-implements pos_self_service_weighing_base.AbstractSelfServiceWeighingScreen
, which I'm not sure is intentional. Can you inherit the latter template without changing it for other inheritors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked with @robinkeunen about this. We can do primary inheritance here as described in my previous comment, but there's a chance that the primary inheritance would be more lines of code in a much less transparent way. e.g. insert a button here, insert a button there, etc.
For developer ease, it may be nice to just see the simple hierarchy like in the quoted code. The hierarchy is sufficiently small that the repetition is barely a problem. And there would be repetition, because there will be other screens that re-implement pos_self_service_weighing_base.AbstractSelfServiceWeighingScreen
. Furthermore, although we currently think that other implementations of AbstractSelfServiceWeighingScreen
will look incredibly similar, this may not always be the case.
But… For the time being, it's still repetition. And because this hierarchy kind of depends on pos.css
from the main module to display well, it's probably better to do primary inheritance?
Your thoughts @huguesdk ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@huguesdk we discussed this with Carmen. It is now obvious to us wether primary inheritance is better (less code - maybe) or worse (lacks clarity) then redefining a template. What is your point of view ?
import PosComponent from "point_of_sale.PosComponent"; | ||
import Registries from "point_of_sale.Registries"; | ||
|
||
class SelfServiceWeighingTareScreen extends PosComponent {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this not extend AbstractSelfServiceWeighingScreen
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<t | ||
t-name="pos_self_service_weighing_tare.SelfServiceWeighingTareScreenButton" | ||
owl="1" | ||
> | ||
<button class="button"> | ||
<t t-esc="name" /> | ||
<i t-attf-class="fa {{ faSymbol }}" /> | ||
</button> | ||
</t> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done (and other similar)
SelfServiceWeighingPrintTareButton.template = | ||
"pos_self_service_weighing_tare.SelfServiceWeighingPrintTareButton"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can set the template to pos_self_service_weighing_base.SelfServiceWeighingControlButton
.
636b82f
to
759e250
Compare
0cd9587
to
86c297c
Compare
86c297c
to
b15ce82
Compare
This is a heavily WIP module to use the Odoo POS as a self-service terminal for customers. Customers will be able to:
It'll be a while before this is finished. Opening the PR early for early reviews from colleagues. Other OCA contributors needn't look at this PR for the moment.