"
+ html += "
"
+
for area in areas:
- html += f"
"
- html += f"
"
- html += f"| {area.name} | | Datum | Gültig bis |
"
+ html += ""
+
+ # Bereichsüberschrift
+ html += f"""
+
+ |
+ {area.name}
+ |
+
+
+ |
+ |
+ |
+
+ """
+
machines = self.env['ows.machine'].search([('area_id', '=', area.id)], order="name")
+
for machine in machines:
access = self.env['ows.machine.access'].search([
('partner_id', '=', partner.id),
('machine_id', '=', machine.id),
], limit=1)
icon = "" if access else ""
- date_granted = access.date_granted.strftime('%Y-%m-%d') if access and access.date_granted else ""
- date_expiry = access.date_expiry.strftime('%Y-%m-%d') if access and access.date_expiry else ""
+ date_granted = access.date_granted.strftime('%Y-%m-%d') if access and access.date_granted else "-"
+ date_expiry = access.date_expiry.strftime('%Y-%m-%d') if access and access.date_expiry else "-"
+
html += f"""
- |
- {icon} |
- {date_granted} |
- {date_expiry} |
+ |
+ {date_granted} |
+ {date_expiry} |
"""
- html += "
"
- html += ""
+
+ html += "
"
+
+ html += "
"
partner.machine_access_html = html
+
+
@api.model
def migrate_existing_partners(self):
"""
@@ -283,6 +330,31 @@ class ResPartner(models.Model):
_logger.info(f"[OWS Migration] ✅ Maschinenfreigaben erstellt: {count_created}")
self.env.cr.commit()
+
+ @api.model
+ def archive_partners_without_users(self):
+ """
+ Archiviert alle Partner (res.partner), die keine Benutzer (res.users) sind.
+ """
+ Partner = self.env['res.partner']
+ User = self.env['res.users']
+
+ # IDs aller Partner, die ein Benutzerkonto haben
+ user_partner_ids = User.search([]).mapped('partner_id').ids
+
+ # Alle Partner ohne Benutzerkonto
+ partners_to_archive = Partner.search([
+ ('id', 'not in', user_partner_ids),
+ ('active', '=', True),
+ ])
+
+ count = len(partners_to_archive)
+ partners_to_archive.write({'active': False})
+ for p in partners_to_archive:
+ _logger.debug(f"[OWS] Archiviert Partner: {p.name} (ID {p.id})")
+ _logger.info(f"[OWS] Archiviert {count} Partner ohne Benutzerkonto.")
+ self.env.cr.commit()
+
class OwsUser(models.Model):
_name = 'ows.user'
diff --git a/models/pos_order.py b/models/pos_order.py
new file mode 100644
index 0000000..71ae7c2
--- /dev/null
+++ b/models/pos_order.py
@@ -0,0 +1,49 @@
+from odoo import models, fields, api
+from collections import defaultdict
+
+#import debugpy
+import logging
+
+_logger = logging.getLogger(__name__)
+_logger.info("✅ pos_order.py geladen")
+
+# debugpy.listen(("0.0.0.0", 5678))
+print("✅ debugpy wartet auf Verbindung (Port 5678) ...")
+# Optional: Starte erst, wenn VS Code verbunden ist
+#debugpy.wait_for_client()
+
+class PosOrder(models.Model):
+ _inherit = 'pos.order'
+
+ def _process_order(self, order, draft, existing_order):
+ pos_order_id = super(PosOrder, self)._process_order(order, draft, existing_order)
+ pos_order = self.browse(pos_order_id)
+
+ training_products = self.env['ows.machine.training'].search([])
+ product_map = defaultdict(list)
+ for tp in training_products:
+ product_map[tp.training_id.product_tmpl_id.id].append(tp.machine_id.id)
+
+ partner = pos_order.partner_id
+ if not partner:
+ _logger.info("🟡 POS-Bestellung ohne Partner – keine Freigabe möglich")
+ return pos_order_id
+
+ for line in pos_order.lines:
+ product_tmpl_id = line.product_id.product_tmpl_id.id
+ machine_ids = product_map.get(product_tmpl_id, [])
+ _logger.info("🔍 Prüfe Produkt %s → Maschinen IDs: %s", line.product_id.display_name, machine_ids)
+ for machine_id in machine_ids:
+ already_exists = self.env['ows.machine.access'].search([
+ ('partner_id', '=', partner.id),
+ ('machine_id', '=', machine_id)
+ ], limit=1)
+ if not already_exists:
+ self.env['ows.machine.access'].create({
+ 'partner_id': partner.id,
+ 'machine_id': machine_id,
+ 'granted_by_pos': True
+ })
+ _logger.info("✅ Maschinenfreigabe erstellt: %s für %s", machine_id, partner.name)
+
+ return pos_order_id
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
index d011792..022703c 100644
--- a/security/ir.model.access.csv
+++ b/security/ir.model.access.csv
@@ -2,7 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_ows_machine_access_user,ows.machine.access,model_ows_machine_access,base.group_user,1,1,1,1
access_ows_machine_user,ows.machine,model_ows_machine,base.group_user,1,1,1,1
access_ows_machine_product_user,ows.machine.product,model_ows_machine_product,base.group_user,1,1,1,1
+access_ows_machine_training_user,access_ows_machine_training_user,model_ows_machine_training,base.group_user,1,1,1,1
access_ows_machine_area,ows.machine.area,model_ows_machine_area,base.group_user,1,1,1,1
access_ows_user,ows.user,model_ows_user,base.group_user,1,1,1,1
-access_ows_machine_training_user,ows.machine.training,model_ows_machine_training,base.group_user,1,1,1,1
-
+access_ows_machine_training,ows.machine.training,model_ows_machine_training,base.group_user,1,1,1,1
diff --git a/static/src/css/pos.css b/static/src/css/pos.css
new file mode 100644
index 0000000..0748dde
--- /dev/null
+++ b/static/src/css/pos.css
@@ -0,0 +1,2622 @@
+/* --- Fonts --- */
+
+@font-face{
+ font-family: 'Inconsolata';
+ src: url(../fonts/Inconsolata.otf);
+}
+
+/* --- Styling of OpenERP Elements --- */
+.ui-dialog, .modal-dialog {
+ background: white;
+ padding: 10px;
+ border-radius: 3px;
+ font-family: sans-serif;
+ box-shadow: 0px 10px 40px rgba(0,0,0,0.4);
+ position: absolute;
+ top: 30px;
+ height: 400px;
+ overflow: scroll;
+}
+.ui-dialog button, .modal-dialog button {
+ padding: 8px;
+ min-width: 48px;
+}
+.ui-dialog .ui-icon-closethick{
+ float: right;
+}
+div.modal.in {
+ position: absolute;
+ background: white;
+ padding: 20px;
+ box-shadow: 0px 10px 20px black;
+ border-radius: 3px;
+ max-width: 600px;
+ max-height: 400px;
+ margin-top: -200px;
+ margin-left: -300px;
+ top: 50%;
+ left: 50%;
+}
+
+/* --- Generic Restyling and Resets --- */
+
+html {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ font-family: sans-serif;
+}
+
+table {
+ border-spacing: 0px;
+ border-collapse: collapse;
+}
+td {
+ padding: 0px;
+}
+
+.oe_hidden{
+ display: none !important;
+}
+.oe_invisible{
+ visibility: hidden !important;
+}
+.clearfix:after {
+ content:" ";
+ display: block;
+ visibility: hidden;
+ line-height: 0;
+ height: 0;
+ clear: both;
+}
+
+
+.pos input::-webkit-outer-spin-button,
+.pos input::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+.pos button{
+ box-shadow: none;
+ outline: none;
+ border: none;
+ font-family: 'Lato';
+}
+.pos button:hover{
+ background: default;
+}
+.pos textarea {
+ font-family: "Lato";
+ font-size: 20px;
+ color: #444;
+ padding: 10px;
+ border-radius: 3px;
+ border: none;
+ box-shadow: 0px 0px 0px 1px rgb(220,220,220) inset;
+}
+.pos textarea:focus {
+ outline: none;
+ box-shadow: 0px 0px 0px 3px #6EC89B;
+}
+
+
+.pos .oe_hidden{
+ display: none !important;
+}
+
+.pos ul, .pos li {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+}
+
+.pos {
+ background: #d3d3d3
+ direction: ltr;
+ padding: 0;
+ margin: 0;
+ background-color: #f0eeee;
+ font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial;
+ color: #555555;
+ font-size: 12px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+ text-shadow: none;
+ overflow: hidden;
+}
+
+/* ********* The black loading screen ********* */
+
+.pos .loader{
+ background-color: #222;
+ position:absolute;
+ left:0px;
+ top:0px;
+ width:100%;
+ height:100%;
+ z-index: 999;
+ text-align: center;
+ font-family: Lato;
+ color: #555555;
+}
+
+.pos .loader-feedback{
+ width: 400px;
+ height: 160px;
+ margin: -60px -200px;
+ position: absolute;
+ left: 50%; top: 50%;
+ text-align: center;
+}
+.pos .loader-feedback h1{
+ font-weight: 300;
+}
+.pos .loader-feedback .progressbar{
+ background: rgb(73,73,73);
+ height: 1px;
+}
+.pos .loader-feedback .progressbar > .progress{
+ height: 100%;
+ background: white;
+ width: 0%;
+ box-shadow: 0px 0px 5px rgba(255,255,255,0.35);
+}
+.pos .loader-feedback .button{
+ display: inline-block;
+ margin: 25px auto;
+ line-height: 42px;
+ padding: 0px 16px;
+ font-size: 20px;
+ font-weight: 300;
+ border: solid 1px;
+ border-radius: 5px;
+ cursor: pointer;
+}
+.pos .loader-feedback .button:active{
+ color: #222;
+ background: #555555;
+}
+/* ********* Generic Layout Constructs ********* */
+
+.pos .window{
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 100%;
+ display: table;
+ border: none;
+ overflow: hidden;
+}
+.pos .window .subwindow{
+ display: table-row;
+ width: 100%;
+ height: 100%;
+}
+.pos .window .subwindow.collapsed{
+ height: 0px;
+}
+.pos .window .subwindow-container .collapsed{
+ height: 0px;
+}
+.pos .subwindow .subwindow-container{
+ display: table-cell;
+ position: relative;
+}
+/* firefox seems to ignore the relative positionning of the subwindow-container
+ * putting this inside subwindow-container fixes it.
+ */
+.pos .subwindow .subwindow-container-fix{
+ height: 100%;
+ position: relative;
+}
+
+.pos .clientlist-screen .window,
+.pos .clientlist-screen .full-content .subwindow{
+ display: block;
+}
+.pos .clientlist-screen .full-content .subwindow-container{
+ display: block;
+ height: 100%;
+}
+.pos .clientlist-screen .full-content .subwindow.collapsed,
+.pos .clientlist-screen .full-content .subwindow-container.collapsed{
+ height: auto;
+}
+
+/* ---- Scrollers ----- */
+
+.pos .scroller-container{
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+}
+.pos .scroller{
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+}
+.pos .scroller.horizontal{
+ overflow-y: hidden;
+ overflow-x: auto;
+}
+.pos .scroller-content{
+ -webkit-transform: translate3d(0,0,0);
+}
+.pos .scroller-container ::-webkit-scrollbar{
+ width: 10px;
+ height: 10px;
+}
+.pos .scroller-container ::-webkit-scrollbar-track{
+ background: rgb(224,224,224);
+ border-left: solid 1px rgb(200,200,200);
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.pos .scroller-container ::-webkit-scrollbar-thumb{
+ background: rgb(168,168,168);
+ min-height: 30px;
+}
+
+/* ********* Generic element styling ********* */
+
+.pos a {
+ text-decoration: none;
+ color: #555555;
+}
+.pos button, .pos a.button {
+ display: inline-block;
+ cursor: pointer;
+ padding: 4px 10px;
+ font-size: 11px;
+ border: 1px solid #cacaca;
+ background: #e2e2e2;
+ border-radius: 3px;
+}
+.pos ul, .pos ol {
+ padding: 0;
+ margin: 0;
+}
+.pos li {
+ list-style-type: none;
+}
+.pos .pos-right-align {
+ text-align: right;
+}
+.pos .pos-center-align {
+ text-align: center;
+}
+.pos .pos-disc-font {
+ font-size: 12px;
+ font-style:italic;
+ color: #808080;
+}
+
+/* ********* The black header bar ********* */
+
+
+.pos .pos-topheader {
+ position:absolute;
+ left:0;
+ top:0;
+ width: 100%;
+ height: 48px;
+ margin:0;
+ padding:0;
+ color: gray;
+ background: #ff0000;
+}
+
+/* a) The left part of the top-bar */
+
+.pos .pos-branding{
+ position: absolute;
+ display: table-cell;
+ left:0;
+ top:0;
+ width:439px;
+ height:100%;
+ margin:0;
+ padding:0;
+ border-right: 1px solid #373737;
+ text-align:left;
+ line-height:100%;
+ vertical-align: middle;
+}
+.pos .pos-logo {
+ height: 35px;
+ margin-left: 10px;
+ margin-top: 5px;
+ vertical-align:middle;
+}
+.pos .pos-branding .username{
+ float:right;
+ color:#DDD;
+ font-size:16px;
+ margin-right:32px;
+ line-height: 48px;
+ font-style:italic;
+ cursor: pointer;
+}
+
+/* b) The right part of the top-bar */
+
+.pos .pos-rightheader {
+ position: absolute;
+ right:0;
+ top:0;
+ height:100%;
+ display: -webkit-flex;
+ display: flex;
+ overflow : hidden;
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+}
+.pos .pos-rightheader > * {
+ border-right: 1px solid #292929;
+}
+
+.pos .new-order-button{
+ text-align: center;
+ width : 100%;
+ height: 48px;
+ background : #d3d3d3;
+/* overflow: auto; */
+}
+
+.pos .order-button{
+ color: #f0f0f0;
+ display: inline-block;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ padding-left: 6px;
+ margin: 2px;
+ background: #8b8b8b;
+ border-radius: 3px;
+ vertical-align: top;
+ line-height: 30px;
+ text-align: left;
+ box-shadow: 0px -5px 10px -6px rgb(82,82,82) inset;
+ cursor: pointer;
+ width : 98%;
+ min-width: 45px;
+/* overflow: auto; */
+}
+
+.pos .order-button:first-child {
+ margin-left: 0px;
+}
+
+.pos .orders .order-button {
+ display: flex;
+ justify-content: flex-start; /* falls nötig */
+ flex-direction: row-reverse;
+ align-items: center;
+ gap: 0.5em;
+}
+
+
+.pos .order-button.selected{
+ font-weight: 900;
+ background: #EEEEEE;
+ color: rgb(75,75,75);
+ height: 35px;
+ line-height: 35px;
+ border-bottom: solid 1px rgb(196, 196, 196);
+ border-right: solid 0px eeeeee;
+ box-shadow: none;
+ -webkit-flex-shrink: 0;
+ flex-shrink: 0;
+ width : 98%;
+}
+
+.pos .order-button .order-sequence{
+ font-size: 16px;
+ width: 99%
+ font-weight: 800;
+ vertical-align: middle;
+}
+.pos .order-button.selected .order-sequence{
+ color: white;
+ background: black;
+ display: inline-block;
+ line-height: 24px;
+ min-width: 24px;
+ border-radius: 12px;
+ margin-right: 4px;
+ margin-left: -4px;
+}
+
+.pos .order-button.square {
+ margin-left: 1px;
+ /* background: #5c5c5c; */
+ /* color: rgb(160, 160, 160); */
+ /* font-size: 18px; */
+ text-align: center;
+ line-height: 36px;
+ width: 45%;
+ /* margin-top: 10px; */
+ /* margin-bottom: 10px; */
+ /* padding: 10px; */
+}
+.pos .order-button:not(.square) > .fa {
+ font-size: 16px;
+ vertical-align: middle;
+ margin-right: 4px;
+}
+.pos .order-button .order-sequence{
+ font-size: 16px;
+ font-weight: 800;
+}
+
+.pos .order-selector {
+ width: 220px;
+ position: absolute;
+ height: 100%;
+ top: 48px;
+
+ display: -webkit-flex;
+ display: flex;
+ -webkit-flex: 1;
+ flex: 1;
+ direction: rtl;
+}
+
+.pos .orders {
+ width: 98%;
+ position: absolute;
+ vertical-align: top;
+ margin-left: 0px;
+ top: 48px;
+ /* make it wrap to multiple lines and get a scrollbar */
+ overflow: auto;
+ scrollbar-color: gray gray;
+ box-sizing: border-box;
+ height: calc(100% - 2 * 48px); /* The pixels is the value of top */
+ direction: rtl;;
+}
+
+/* c) The session buttons */
+
+.pos .pos-rightheader .header-button{
+ float: right;
+ height: 48px;
+ padding-left: 16px;
+ padding-right: 16px;
+ border-right: 1px solid #292929;
+ border-left: 1px solid #292929;
+ color: #DDD;
+ line-height: 48px;
+ text-align: center;
+ cursor: pointer;
+
+ -webkit-transition-property: background;
+ -webkit-transition-duration: 0.2s;
+ -webkit-transition-timing-function: ease-out;
+}
+.pos .pos-rightheader .header-button:last-child{
+ border-left: 1px solid #3a3a3a;
+}
+.pos .pos-rightheader .header-button:active{
+ background: rgba(0,0,0,0.2);
+ color:#EEE;
+}
+.pos .pos-rightheader .header-button.confirm {
+ background: #359766;
+ color: white;
+ font-weight: bold;
+}
+
+/* c) The notifications indicator */
+
+.pos .oe_status{
+ float:right;
+ color: white;
+ padding: 14px;
+ line-height: 20px;
+ font-size: 30px;
+ vertical-align:middle;
+ font-style: italic;
+ font-weight: bold;
+ cursor:pointer;
+}
+
+.pos .oe_status .username{
+ margin-right: 200px;
+}
+
+.pos .oe_status.oe_inactive{
+ cursor: default;
+}
+.pos .oe_status .oe_icon{
+ display:inline-block;
+ cursor:pointer;
+ width:20px; height:16px;
+ color: white;
+}
+.pos .oe_status .oe_red,
+.pos .oe_icon.oe_red {
+ color: rgb(197, 52, 0);
+}
+.pos .oe_status .oe_green,
+.pos .oe_icon.oe_green {
+ color: rgb(94, 185, 55);
+}
+.pos .oe_status .oe_orange,
+.pos .oe_icon.oe_orange {
+ color: rgb(239, 153, 65);
+}
+.pos .oe_link_icon{
+ cursor:pointer;
+}
+/* ********* Contains everything below the bar ********* */
+.pos .pos-content {
+ width: 80%; /* 200px is the value of the left property */
+ left: 20%;
+ right: 0%;
+
+ position: absolute;
+ top: 48px;
+ bottom: 0;
+ background: #F0EEEE;
+}
+
+/* ********* The leftpane contains the order, numpad and paypad ********* */
+
+.pos .leftpane {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ position:absolute;
+ left:0;
+ width:440px;
+ top:0px;
+ bottom:0;
+ border-right: solid 1px #CECBCB;
+ border-right: solid 3px #787878;
+ background: #e2e2e2;
+}
+
+.pos .leftpane .pads {
+ border-top: solid 3px rgb(110, 200, 155);
+}
+
+/* ********* The control buttons ********* */
+
+.pos .control-buttons {
+ display: -webkit-flex;
+ display: flex;
+ -webkit-flex-flow: row wrap;
+ flex-flow: row wrap;
+ padding: 8px 16px 0px 11px;
+ margin-bottom: -6px;
+}
+.pos .control-button {
+ -webkit-flex-grow: 1;
+ flex-grow: 1;
+ background: #e2e2e2;
+ border: solid 1px #bfbfbf;
+ display: inline-block;
+ line-height: 38px;
+ min-width: 80px;
+ text-align: center;
+ border-radius: 3px;
+ padding: 0px 10px;
+ font-size: 18px;
+ margin-left: 6px;
+ margin-bottom: 6px;
+ cursor: pointer;
+ overflow: hidden;
+ transition: all linear 150ms;
+}
+.pos .control-button:hover {
+ background: #efefef;
+}
+.pos .control-button:active {
+ background: black;
+ color: white;
+ border-color: black;
+}
+.pos .control-button .fa{
+ margin-right: 4px;
+}
+.pos .control-button .control-button-number {
+ color: rgb(226, 226, 226);
+ background: rgb(85, 85, 85);
+ display: inline-block;
+ height: 28px;
+ vertical-align: middle;
+ font-weight: bold;
+ line-height: 28px;
+ width: 28px;
+ border-radius: 50%;
+ text-align: center;
+ margin-left: -16px;
+ margin-right: 4px;
+}
+
+.pos .control-button.highlight,
+.pos .button.highlight {
+ background: #6EC89B !important;
+ border: solid 1px #64AF8A !important;
+ color: white !important;
+}
+.pos .control-button.altlight,
+.pos .button.altlight {
+ background: #7F82AC !important;
+ border: solid 1px #756A99 !important;
+ color: white !important;
+}
+.pos .control-button.disabled,
+.pos .control-button.disabled:active{
+ background: #e2e2e2;
+ border: solid 1px #BEBEBE;
+ opacity: 0.5;
+ cursor: default;
+ color: inherit;
+}
+
+/* ********* The actionpad (payment, set customer) ********* */
+
+.pos .actionpad {
+ display: inline-block;
+ float: left;
+ padding: 0;
+ margin: 16px;
+ margin-top: 8px;
+ margin-right: 0;
+ text-align: center;
+ vertical-align: top;
+ width: 186px;
+ border: none;
+ border-radius: 0;
+ border-top: 1px solid;
+ border-left: 1px solid;
+ border-color: #bfbfbf;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+.pos .actionpad .button {
+ position: relative;
+ display: block;
+ height: 54px;
+ width: 100%;
+ font-weight: bold;
+ vertical-align: middle;
+ color: #555555;
+ font-size: 14px;
+ border-radius: 0;
+ border: none;
+ border-right: 1px solid;
+ border-bottom: 1px solid;
+ border-color: #bfbfbf;
+ transition: all 150ms linear;
+}
+.pos .actionpad .button:hover {
+ background: #efefef;
+}
+.pos .actionpad .button:active {
+ background: black;
+ border-color: black;
+ color: white;
+}
+.pos .actionpad .button:first-child {
+ border-top-left-radius: 4px;
+}
+.pos .actionpad .button:last-child {
+ border-bottom-left-radius: 4px;
+}
+.pos .actionpad .button.pay {
+ height: 162px;
+}
+.pos .actionpad .button.pay .pay-circle {
+ display: block;
+ font-size: 32px;
+ line-height: 54px;
+ padding-top: 6px;
+ background: rgb(86, 86, 86);
+ color: white;
+ width: 60px;
+ margin: auto;
+ border-radius: 30px;
+ margin-bottom: 10px;
+}
+.pos .actionpad .button.pay .pay-circle .fa {
+ position: relative;
+ top: -1px;
+ left: 3px;
+}
+
+.pos .actionpad .button.set-customer{
+ padding-left: 40px;
+ padding-right: 40px;
+}
+.pos .actionpad .button.set-customer.decentered {
+ padding-left: 40px;
+ padding-right: 5px;
+}
+.pos .actionpad .button .fa-user {
+ position: absolute;
+ left: 13px;
+ top: 13px;
+ margin-right: 8px;
+ font-size: 18px;
+ background: rgba(255, 255, 255, 0.5);
+ line-height: 30px;
+ width: 30px;
+ border-radius: 100%;
+}
+
+/* ********* The Numpad ********* */
+
+.pos .numpad {
+ display: inline-block;
+ float: right;
+ text-align: center;
+ width: 216px;
+ margin: 16px;
+ margin-top: 8px;
+ margin-left: 0px;
+ border: none;
+ border-radius: 0;
+ border-top: 1px solid;
+ border-color: #bfbfbf;
+ border-top-right-radius: 4px;
+}
+.pos .numpad button {
+ float: left/*rtl:ignore*/; /* rtlcss forced to keep ltr */
+ height: 54px;
+ width: 54px;
+ font-weight: bold;
+ vertical-align: middle;
+ color: #555555;
+ border-radius: 0;
+ border: none;
+ border-right: 1px solid;
+ border-bottom: 1px solid;
+ border-color: #bfbfbf;
+ transition: all 150ms linear;
+}
+.pos .numpad button:hover {
+ background: #efefef;
+}
+.pos .numpad button:active {
+ background: black;
+ color: white;
+ border-color: transparent;
+}
+.pos .numpad button:nth-child(4) {
+ border-top-right-radius: 4px;
+}
+.pos .numpad button:last-child {
+ border-bottom-right-radius: 4px;
+}
+.pos .input-button {
+ font-size: 24px;
+}
+.pos .mode-button {
+ font-size: 14px;
+}
+.pos .mode-button.selected-mode {
+ color: white;
+ background: #6EC89B;
+ border-color: transparent;
+}
+.pos .mode-button.selected-mode:hover {
+ background: #6EC89B;
+ color: white;
+ border-color: transparent;
+}
+.pos .numpad .disabled-mode, .pos .numpad .disabled-mode:hover {
+ background: #c7c7c7;
+ color: #a5a1a1;
+ cursor: not-allowed;
+}
+
+/* ********* The right pane contains the screens and headers ********* */
+
+.pos .rightpane {
+ position: absolute;
+ top: 0;
+ bottom:0;
+ left: 440px;
+ right: 0;
+ vertical-align: top;
+ -webkit-transform: translate3d(0,0,0);
+}
+
+.pos .rightpane-header {
+ padding: 0;
+ height: 48px;
+ border-bottom: 1px solid #c7c7c7;
+ background: #d3d3d3;
+ text-align: center;
+}
+
+/* ********* The product list ********* */
+
+.pos .product-list {
+ padding: 10px;
+ text-align: left;
+ -webkit-transform: translate3d(0,0,0);
+}
+
+.pos .product-list-scroller{
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ width:100%;
+ height:100%;
+ overflow: hidden;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ -webkit-transform: translate3d(0,0,0);
+
+}
+.pos .product-list-container {
+ position:absolute;
+ top:0px;
+ bottom:0px;
+ left:0px;
+ right:0px;
+}
+
+/* a) the product list navigation bar */
+
+.pos .breadcrumbs{
+ display: inline-block;
+ text-align: left;
+ float:left;
+}
+.pos .breadcrumb{
+ float: left;
+ display: inline-block;
+ line-height: 48px;
+ height: 48px;
+ min-width: 48px;
+}
+.pos .breadcrumb:last-child {
+ padding-right: 3px;
+ border-right: 1px solid #c5c5c5;
+}
+.pos .breadcrumb-button {
+ display: inline-block;
+ padding: 0 9px;
+ vertical-align: top;
+ color: #808080;
+ font-size: 14px;
+ cursor: pointer;
+}
+.pos .breadcrumb-button.breadcrumb-home {
+ line-height: 50px;
+ padding: 0;
+ width: 50px;
+ font-size: 25px;
+ text-align: center;
+}
+
+.pos .breadcrumb-arrow{
+ width: 28px;
+}
+.pos .breadcrumb-homeimg {
+ width: 27px;
+ margin: 12px 6px;
+}
+
+/* b) the search box */
+
+.pos .searchbox {
+ position: absolute;
+ right: 2px;
+}
+.pos .searchbox input {
+ width: 100px;
+ border: 1px solid #cecbcb;
+ padding: 10px 20px;
+ padding-left: 38px;
+ padding-right: 33px;
+ margin: 6px;
+ background-color: white;
+ border-radius: 20px;
+ font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial;
+ font-size: 13px;
+}
+.pos .searchbox input:focus {
+ outline: none;
+ box-shadow: 0px 0px 0px 2px rgb(153, 153, 255) inset;
+ color: rgb(153, 153, 255);
+}
+
+.pos .search-clear {
+ position: absolute;
+ top: 9px;
+ width: 30px;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.search-clear.left {
+ left: 11px;
+ color: #808080;
+}
+
+.search-clear.right {
+ left: 145px;
+ color: #808080;
+ cursor: pointer;
+}
+
+/* c) the categories list */
+
+.pos .categories {
+ position: relative;
+ border-bottom: solid 3px rgb(110, 200, 155);
+}
+.pos .categories h4 {
+ display: inline-block;
+ margin: 9px 5px;
+}
+.pos .category-list-scroller{
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ width:100%;
+ height:100%;
+ max-height:60vh;
+ overflow: hidden;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ -webkit-transform: translate3d(0,0,0);
+
+}
+.pos .category-list {
+ text-align: left;
+ padding: 10px;
+ background: rgb(229, 229, 229);
+ border-bottom: 1px solid #cecece;
+}
+.pos .category-list.simple {
+ padding: 0px;
+ background: #cecece;
+ display: -webkit-flex;
+ display: flex;
+ -webkit-flex-flow: row wrap;
+ flex-flow: row wrap;
+ border-bottom: none;
+}
+
+
+/* d) the category button */
+
+.pos .category-button {
+ position: relative;
+ vertical-align: top;
+ display: inline-block;
+ font-size: 11px;
+ margin: 8px !important;
+ width: 120px;
+ height:120px;
+ background:#fff;
+ border: 1px solid #d7d7d7;
+ border-radius: 3px;
+ border-bottom-width: 3px;
+ cursor: pointer;
+}
+
+.pos .category-simple-button{
+ position: relative;
+ display: inline-block;
+ font-size: 14px;
+ margin-right: 1px;
+ margin-bottom: 1px;
+ padding: 5px 12px;
+ line-height: 32px;
+ flex-grow: 1;
+ -webkit-flex-grow: 1;
+ cursor: pointer;
+ background: #e2e2e2;
+}
+.pos .category-simple-button:active{
+ color: white;
+ background: black;
+
+ -webkit-transition-property: background, border;
+ -webkit-transition-duration: 0.2s;
+ -webkit-transition-timing-function: ease-out;
+}
+
+
+
+.pos .category-button .category-img {
+ position: relative;
+ width: 120px;
+ height: 100px;
+ text-align: center;
+ cursor: pointer;
+}
+
+.pos .category-button .category-img img {
+ max-height: 100px;
+ max-width: 120px;
+ vertical-align: middle;
+}
+
+.pos .category-button .category-name {
+ position: absolute;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ bottom: 0;
+ top: auto;
+ line-height: 14px;
+ width: 100%;
+ /* for some reason the -90deg orientation doesn't match the -webkit-linear-gradient. It should be 180deg here.
+ * webkit also insists on rendering *both* gradients instead of only the native one. So it doesn't looks right. ugh.
+ background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1)); */
+ /*background:#FFF;*/
+ padding: 3px;
+ padding-top: 15px;
+ color: #7C7BAD;
+}
+
+/* e) the product */
+
+.pos .product {
+ position:relative;
+ vertical-align: top;
+ display: inline-block;
+ line-height: 100px;
+ font-size: 11px;
+ margin: 8px !important;
+ width: 122px;
+ height:115px;
+ background:#fff;
+ border: 1px solid #e2e2e2;
+ border-radius: 3px;
+ border-bottom-width: 3px;
+ overflow: hidden;
+ cursor: pointer;
+}
+
+.pos .product .product-img {
+ position: relative;
+ width: 120px;
+ height: 100px;
+ background: white;
+ text-align: center;
+}
+
+.pos .product .product-img img {
+ max-height: 100px;
+ max-width: 120px;
+ vertical-align: middle;
+}
+
+.pos .product .price-tag {
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ vertical-align: top;
+ color: white;
+ line-height: 13px;
+ background: #7f82ac;
+ padding: 2px 5px;
+ border-radius: 2px;
+}
+
+.pos .product .product-name {
+ position: absolute;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ bottom:0;
+ top:auto;
+ line-height: 14px;
+ width:100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ background: -webkit-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
+ background: -moz-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
+ background: -ms-linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
+ /* troublesome in latest webkit
+ background: linear-gradient(-90deg,rgba(255,255,255,0),rgba(255,255,255,1), rgba(255,255,255,1));
+ */
+ /*background:#FFF;*/
+ padding: 3px;
+ padding-top:15px;
+}
+
+
+/* ********* The Screens ********* */
+
+.pos .screen {
+ position:absolute;
+ text-align: center;
+ top:0px;
+ bottom:0px;
+ width:100%;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+ background: #d3d3d3;
+}
+.pos .screen header h2 {
+ margin-top: 0px;
+ padding-top: 7px;
+}
+.pos .screen p{
+ font-size: 18px;
+}
+.pos .dialog{
+ width: 500px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 50px;
+ text-align: center;
+}
+.pos .dialog p{
+ font-size: 25px;
+ margin-top: 10px;
+ color: #5a5a5a;
+}
+
+/* a) Generic Screen Layout Constructs */
+
+.screen .screen-content{
+ /*margin: 0px auto;*/
+ left: 0px;
+ max-width: 1200px;
+ text-align: left;
+ height: 100%;
+ overflow: hidden;
+ position: relative;
+ background: #eeeeee;
+}
+
+@media screen and (min-width: 1024px) {
+ .screen .screen-content{
+ border-left: dashed 1px rgb(215,215,215);
+ border-right: dashed 1px rgb(215,215,215);
+ }
+}
+
+.screen .top-content{
+ position: absolute;
+ left: 0px; top: 0px; right: 0px;
+ height: 64px;
+ border-bottom: dashed 1px rgb(215,215,215);
+ text-align: center;
+}
+.screen .top-content .button {
+ position: absolute;
+ top: 0px;
+ line-height: 32px;
+ padding: 3px 13px;
+ font-size: 20px;
+ background: rgb(230, 230, 230);
+ margin: 12px;
+ border-radius: 3px;
+ border: solid 1px rgb(209, 209, 209);
+ cursor: pointer;
+ transition: all 150ms linear;
+}
+.screen .top-content .button:hover {
+ background: #efefef;
+}
+.screen .top-content .button:active {
+ background: black;
+ border-color: black;
+ color: white;
+}
+.screen .top-content .button.highlight {
+ background: rgb(110,200,155);
+ color: white;
+ border: solid 1px rgb(110,200,155);
+}
+.screen .top-content .button.highlight:hover {
+ background: rgb(120,210,165);
+}
+.screen .top-content .button.back {
+ left: 0px;
+ margin-left: 16px;
+}
+.screen .top-content .button.next{
+ right: 0px;
+ margin-right: 16px;
+}
+.screen .left-content{
+ position: absolute;
+ left:0px; top: 64px; bottom: 0px;
+ right:50%;
+ overflow-x: hidden;
+ overflow-y: auto;
+ border-right: dashed 1px rgb(215,215,215);
+}
+.screen .left-content.pc40{
+ right: 66%;
+}
+.screen .right-content{
+ position: absolute;
+ right:0px; top: 64px; bottom: 0px;
+ left:50%;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.screen .right-content.pc60{
+ left:34%;
+}
+.screen .centered-content{
+ position: absolute;
+ right:25%; top: 64px; bottom: 0px;
+ left:25%;
+ border-right: dashed 1px rgb(215,215,215);
+ border-left: dashed 1px rgb(215,215,215);
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.screen .full-content{
+ position: absolute;
+ right: 0%; top: 65px; bottom: 0px;
+ left: 0%;
+}
+
+/* a) Layout for the Product Screen */
+
+.pos .screen .layout-table {
+ border:none;
+ width:100%;
+ height:100%;
+}
+
+.pos .screen .header-row {
+ border:none;
+ width:100%;
+ height:0px;
+}
+
+.pos .screen .header-cell{
+ border:none;
+ width:100%;
+ height:0px;
+}
+.pos .screen .content-row {
+ width:100%;
+ height:100%;
+}
+.pos .screen .content-cell{
+ width:100%;
+}
+.pos .screen .content-cell .content-container{
+ height:100%;
+ position:relative;
+}
+
+
+/* b) The payment screen */
+
+.pos .payment-numpad {
+ display: inline-block;
+ width: 50%;
+ box-sizing: border-box;
+ padding: 16px;
+ text-align: center;
+ float: left;
+}
+.pos .payment-numpad .numpad {
+ float: none;
+ border-radius: 4px;
+ border-top: 1px solid;
+ border-left: 1px solid;
+ border-color: #cacaca;
+ width: 296px;
+ overflow: hidden;
+ margin: 0;
+}
+.pos .payment-numpad .numpad button {
+ width: 74px;
+ height: 74px;
+}
+.pos .payment-numpad .numpad button:first-child {
+ border-top-left-radius: 4px;
+}
+.pos .payment-numpad .numpad button:nth-child(16) {
+ border-bottom-left-radius: 4px;
+}
+
+.pos .paymentlines-container {
+ padding: 16px;
+ padding-top: 0;
+ border-bottom: dashed 1px gainsboro;
+ min-height: 154px;
+}
+
+.pos .paymentlines {
+ width: 100%;
+ border-spacing: 0px 10px;
+ border-collapse: inherit;
+}
+.pos .paymentlines .controls {
+ width: 40px;
+}
+.pos .paymentlines .label > * {
+ font-size: 16px;
+ padding: 8px;
+}
+.pos .paymentlines tbody{
+ background: white;
+ border-radius: 3px;
+}
+.pos .paymentline{
+ font-size: 22px;
+}
+.pos .paymentline.selected {
+ font-size: 22px;
+ background: #6EC89B;
+ color: white;
+}
+.pos .paymentline.selected .edit {
+ background: white;
+ color: #6EC89B;
+ outline: 3px blue;
+ box-shadow: 0px 0px 0px 3px #6EC89B;
+ position: relative;
+ border-radius: 3px;
+}
+.pos .paymentline > *{
+ padding: 8px 12px;
+}
+.pos .paymentline .col-due,
+.pos .paymentline .col-tendered,
+.pos .paymentline .col-change {
+ min-width: 90px;
+}
+.pos .paymentline.extra .col-due {
+ border-radius: 0 0 6px 6px;
+ border-top: solid 1px rgb(230, 230, 230);
+ font-weight: bold;
+}
+.pos .paymentline .col-change.highlight {
+ background: rgb(184, 152, 204);
+}
+.pos .paymentline .col-name {
+ font-size: 16px;
+}
+.pos .paymentline .delete-button{
+ cursor: pointer;
+ text-align: center;
+}
+.pos .payment-buttons {
+ display: inline-block;
+ width: 50%;
+ box-sizing: border-box;
+ padding: 16px;
+ padding-left: 0;
+ float: right;
+}
+.payment-screen .payment-buttons .button {
+ background: #e2e2e2;
+ line-height: 73px;
+ font-size: 16px;
+ padding: 0px 8px;
+ border: solid 1px rgb(200,200,200);
+ border-top-width: 0;
+ cursor: pointer;
+ text-align: center;
+ position: relative;
+ transition: background-color, border-color, color 150ms linear;
+}
+.payment-screen .payment-buttons .button:hover {
+ background-color: #efefef;
+}
+.payment-screen .payment-buttons .button:first-child {
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-width: 1px;
+}
+.payment-screen .payment-buttons .button:last-child {
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.payment-screen .payment-buttons .button.highlight:not(:first-child) {
+ margin-top: -1px;
+ border-top: solid 1px;
+}
+.payment-screen .payment-buttons .button:active {
+ background: black;
+ border-color: black;
+ color: white;
+}
+.payment-screen .payment-buttons .button.highlight .fa {
+ border-color: rgba(0, 0, 0, 0.109804);
+ background: rgba(0, 0, 0, 0.0980392);
+}
+.payment-screen .payment-buttons .button .fa {
+ position: absolute;
+ left: 11px;
+ top: 50%;
+ width: 48px;
+ height: 48px;
+ line-height: 48px;
+ margin-top: -25px;
+ vertical-align: middle;
+ border-radius: 26px;
+ border: 1px solid rgba(0,0,0,0.2);
+ border-image-source: initial;
+ border-image-slice: initial;
+ border-image-width: initial;
+ border-image-outset: initial;
+ border-image-repeat: initial;
+ background: rgba(255,255,255,0.4);
+ font-size: 20px;
+ transition: all 150ms linear;
+}
+.payment-screen .paymentlines-empty .total {
+ text-align: center;
+ padding: 24px 0px 18px;
+ font-size: 64px;
+ color: #43996E;
+ text-shadow: 0px 2px white, 0px 2px 2px rgba(0, 0, 0, 0.27);
+}
+.payment-screen .paymentlines-empty .message {
+ text-align: center;
+}
+
+.paymentlines .button {
+ cursor: pointer;
+ border: 1px solid #cacaca;
+}
+.paymentlines .electronic_payment {
+ background: #e2e2e2;
+ border-collapse: unset;
+ text-align: center;
+ font-size: 16px;
+}
+
+/* c) The receipt screen */
+
+.pos .receipt-screen .centered-content .button {
+ line-height: 40px;
+ padding: 3px 13px;
+ font-size: 20px;
+ text-align: center;
+ background: rgb(230, 230, 230);
+ margin: 16px;
+ margin-bottom: 0px;
+ border-radius: 3px;
+ border: solid 1px rgb(209, 209, 209);
+ cursor: pointer;
+}
+
+.pos .pos-receipt-container {
+ font-size: 0.75em;
+ text-align: center;
+ direction: ltr;
+}
+
+.pos .pos-receipt-container > div {
+ text-align: left;
+ width: 300px;
+ background-color: white;
+ margin: 20px;
+ padding: 15px;
+ font-size: 16px;
+ padding-bottom:30px;
+ display: inline-block;
+ border: solid 1px rgb(220,220,220);
+ border-radius: 3px;
+ overflow: hidden;
+}
+
+@page {
+ margin: 0;
+}
+
+@media print {
+ * {
+ color: black !important;
+ }
+ body {
+ margin: 0;
+ color: white !important;
+ /* avoid black background if backgrounds are printed */
+ background: initial;
+ }
+ .o_notification_manager,
+ .oe_leftbar,
+ .oe_loading,
+ .pos .pos-topheader,
+ .pos .pos-leftpane,
+ .pos .keyboard_frame,
+ .pos .receipt-screen header,
+ .pos .receipt-screen .top-content,
+ .pos .receipt-screen .centered-content .button,
+ .pos .receipt-screen .centered-content .print_invoice {
+ display: none !important;
+ }
+
+ .o_action_manager,
+ .pos,
+ .pos .pos-content,
+ .pos .rightpane,
+ .pos .screen,
+ .pos .window,
+ .pos .window .subwindow,
+ .pos .subwindow .subwindow-container{
+ display: block;
+ position: static;
+ height: auto;
+ }
+ .pos{
+ background: white !important;
+ }
+ .pos .rightpane {
+ left: 0px !important;
+ background-color: white;
+ }
+ .pos .receipt-screen {
+ text-align: left;
+ }
+ .pos .receipt-screen .centered-content{
+ position: static;
+ border: none;
+ }
+ .pos .pos-receipt-container {
+ text-align: left;
+ }
+ .pos-actionbar {
+ display: none !important;
+ }
+ .debug-widget{
+ display: none !important;
+ }
+ .pos *{
+ text-shadow: none !important;
+ box-shadow: none !important;
+ background: transparent !important;
+ }
+ .pos .pos-receipt{
+ margin: 0;
+ margin-left: auto !important;
+ margin-right: auto !important;
+ border: none !important;
+ font-size: 13px !important;
+ width: 266px !important;
+ }
+ .o_debug_manager {
+ display: none !important;
+ }
+ .o_chat_window {
+ display: none !important;
+ }
+ .order-selector {
+ display: none !important;
+ }
+ .blockUI {
+ display: none !important;
+ }
+}
+
+/* d) The Scale screen */
+
+.pos .scale-screen .product-price{
+ font-size: 25px;
+ margin: 16px;
+ text-align: center;
+ display: inline-block;
+ width: 40%;
+}
+.pos .scale-screen .computed-price{
+ font-size: 25px;
+ display: inline-block;
+ text-align: right;
+ margin: 16px;
+ margin-top: 0px;
+ padding: 16px;
+ background: white;
+ width: 40%;
+ border-radius: 3px;
+ font-family: Inconsolata;
+ font-weight: bold;
+ text-shadow: 0px 2px 0px rgb(210,210,210);
+ box-shadow: 0px 2px 0px rgb(225,225,225) inset;
+ float: right;
+}
+.pos .scale-screen .buy-product{
+ text-align: center;
+ font-size: 32px;
+ background: rgb(110,200,155);
+ color: white;
+ border-radius: 3px;
+ padding: 16px;
+ margin: 16px;
+ cursor: pointer;
+}
+
+.pos .scale-screen .weight{
+ text-align: right;
+ margin: 16px;
+ background: white;
+ padding: 20px;
+ padding-right: 30px;
+ font-size: 56px;
+ border-radius: 3px;
+ font-family: Inconsolata;
+ text-shadow: 0px 2px 0px rgb(210, 210, 210);
+ box-shadow: 0px 2px 0px rgb(225,225,225) inset;
+}
+
+
+/* e) The Client List Screen */
+
+.pos .clientlist-screen .client-list{
+ font-size: 16px;
+ width: 100%;
+ line-height: 40px;
+}
+.pos .clientlist-screen .client-list th {
+ background: #f7f7f7; /* Hintergrundfarbe des Headers */
+ position: sticky;
+ top: 0;
+ z-index: 10; /* Damit der Header über dem Inhalt bleibt */
+}
+.pos .clientlist-screen .client-list th,
+.pos .clientlist-screen .client-list td {
+ padding: 0px 8px;
+}
+.pos .clientlist-screen .client-list tr{
+ transition: all 150ms linear;
+ background: rgb(230,230,230);
+}
+.pos .clientlist-screen .client-list thead > tr,
+.pos .clientlist-screen .client-list tr:nth-child(even) {
+ background: rgb(247,247,247);
+}
+.pos .clientlist-screen .client-list tr.highlight{
+ transition: all 150ms linear;
+ background: rgb(110,200,155) !important;
+ color: white;
+}
+.pos .clientlist-screen .client-list tr.lowlight{
+ transition: all 150ms linear;
+ background: rgb(216, 238, 227);
+}
+.pos .clientlist-screen .client-list tr.lowlight:nth-child(even){
+ transition: all 150ms linear;
+ background: rgb(227, 246, 237);
+}
+
+.pos .clientlist-screen {
+/* display: grid; */
+ grid-template-columns: repeat(2, 1fr);
+ gap: 0px;
+}
+
+
+.pos .clientlist-screen .client-picture{
+ height: 64px;
+ width: 64px;
+ border-radius: 32px;
+ overflow: hidden;
+ text-align: center;
+ float: left;
+ margin-right: 16px;
+ background: white;
+ position: relative;
+}
+.pos .clientlist-screen .client-picture > img {
+ position: absolute;
+ top: -9999px;
+ bottom: -9999px;
+ right: -9999px;
+ left: -9999px;
+ max-height: 64px;
+ margin: auto;
+}
+.pos .clientlist-screen .client-picture > .fa {
+ line-height: 64px;
+ font-size: 32px;
+}
+.pos .clientlist-screen .client-picture .image-uploader {
+ position: absolute;
+ z-index: 1000;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ opacity: 0;
+ cursor: pointer;
+}
+.pos .clientlist-screen .client-name {
+ font-size: 32px;
+ line-height: 64px;
+ margin-bottom:16px;
+}
+.pos .clientlist-screen .edit-buttons {
+ position: absolute;
+ right: 16px;
+ top: 10px;
+}
+.pos .clientlist-screen .edit-buttons .button{
+ display: inline-block;
+ margin-left: 16px;
+ color: rgb(128,128,128);
+ cursor: pointer;
+ font-size: 36px;
+}
+.pos .clientlist-screen .client-details-box{
+ position: relative;
+ font-size: 16px;
+}
+.pos .clientlist-screen .client-details-left{
+ width: 50%;
+ float: left;
+}
+.pos .clientlist-screen .client-details-right{
+ width: 50%;
+ float: right;
+}
+.pos .clientlist-screen .client-detail{
+ line-height: 24px;
+}
+.pos .clientlist-screen .client-detail > .label{
+ font-weight: bold;
+ display: inline-block;
+ width: 150px;
+ text-align: right;
+ margin-right: 8px;
+}
+.pos .clientlist-screen .client-detail > .briefinglabel{
+ font-weight: bold;
+ display: inline-block;
+
+ text-align: right;
+ margin-right: 8px;
+}
+.pos .clientlist-screen .client-details input,
+.pos .clientlist-screen .client-details select
+{
+ padding: 4px;
+ border-radius: 3px;
+ border: solid 1px #cecbcb;
+ margin-bottom: 4px;
+ background: white;
+ font-family: "Lato","Lucida Grande", Helvetica, Verdana, Arial;
+ color: #555555;
+ width: 150px;
+ font-size: 14px;
+ box-sizing: border-box;
+}
+.pos .clientlist-screen .client-details input.client-name {
+ font-size: 24px;
+ line-height: 24px;
+ margin: 18px 6px;
+ width: 340px;
+}
+.pos .clientlist-screen .client-detail > .empty{
+ opacity: 0.3;
+}
+.pos .clientlist-screen .searchbox{
+ right: auto;
+ margin-left: -90px;
+ margin-top:8px;
+ left: 50%;
+}
+.pos .clientlist-screen .searchbox input{
+ width: 120px;
+}
+.pos .clientlist-screen .button.new-customer {
+ left: 50%;
+ margin-left: 120px;
+}
+
+.pos .clientlist-screen .button.new-registration {
+ right: 0%;
+ /*margin-left: 120px;*/
+}
+
+
+
+/* ********* The OrderWidget ********* */
+
+.pos .order-container{
+ position: absolute;
+ top: 0px;
+ width:100%;
+ height: 100%;
+ background: white;
+}
+
+.pos .order-scroller{
+ width:100%;
+ height:100%;
+ overflow: hidden;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.pos .scrollable-y{
+ overflow: hidden !important;
+ overflow-y: auto !important;
+ -webkit-overflow-scrolling: touch !important;
+}
+
+.pos .order{
+ background: white;
+ padding-bottom: 8px;
+ padding-top: 8px;
+ font-size: 16px;
+ text-align: left;
+ width: 99%;
+ max-width: 500px;
+ -webkit-transform: translate3d(0,0,0);
+}
+
+.pos .order .order-empty {
+ text-align: center;
+ margin: 48px;
+ color: #DDD;
+}
+.pos .order .order-empty .fa {
+ font-size: 64px;
+}
+.pos .order .order-empty h1 {
+ font-size: 20px;
+}
+
+.pos .order .summary{
+ width:100%;
+ text-align:right;
+ font-weight: bold;
+ margin-top:20px;
+ margin-bottom:10px;
+}
+.pos .order .summary .line{
+ float: right;
+ margin-right:15px;
+ margin-left: 15px;
+ padding-top:5px;
+ border-top: solid 2px;
+ border-color:#777;
+}
+.pos .order .summary .total {
+ font-size: 22px;
+}
+.pos .order .summary .line .subentry{
+ font-size: 16px;
+ font-weight: normal;
+ text-align: center;
+}
+.pos .order .summary .line.empty{
+ text-align: right;
+ border-color:#BBB;
+ color:#999;
+}
+
+.pos .order .summary .fidpoints{
+ position: absolute;
+ left: 20px;
+ padding: 10px;
+ color: #6EC89B;
+ background: rgba(110, 200, 155, 0.17);
+ border-radius: 3px;
+}
+
+.submit-kitchen-button {
+ float: left;
+ background: rgb(61, 235, 82);
+ color: white;
+ padding: 12px 20px;
+ margin: 0px 15px;
+ border-radius: 3px;
+ cursor: pointer;
+}
+
+/* ********* The OrderLineWidget ********* */
+
+.pos .order .orderline{
+ width:100%;
+ margin:0px;
+ padding-top:3px;
+ padding-bottom:10px;
+ padding-left:15px;
+ padding-right:15px;
+ cursor: pointer;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-transition: background 250ms ease-in-out;
+ -moz-transition: background 250ms ease-in-out;
+ transition: background 250ms ease-in-out;
+}
+.pos .order .orderline:active{
+ background: rgba(140,143,183,0.05);
+ -webkit-transition: background 50ms ease-in-out;
+ -moz-transition: background 50ms ease-in-out;
+ transition: background 50ms ease-in-out;
+}
+.pos .order .orderline.empty:active{
+ background: transparent;
+ cursor: default;
+}
+
+.pos .order .orderline.selected{
+ background: rgba(140,143,183,0.2);
+ -webkit-transition: background 250ms ease-in-out;
+ -moz-transition: background 250ms ease-in-out;
+ transition: background 250ms ease-in-out;
+ cursor: default;
+}
+.pos .order .orderline .product-name{
+ padding:0;
+ display:inline-block;
+ font-weight: bold;
+ width:80%;
+ overflow:hidden;
+ text-overflow: ellipsis;
+}
+.pos .order .orderline .price{
+ padding:0;
+ font-weight: bold;
+ float:right;
+}
+.pos .order .orderline .info-list{
+ color: #888;
+ margin-left:10px;
+}
+.pos .order .orderline .info-list em{
+ color: #777;
+ font-weight: bold;
+ font-style:normal;
+}
+
+/* ********* SplitBill ********* */
+
+.splitbill-screen .order-info {
+ text-align: center;
+ margin-bottom:20px;
+ padding: 20px 0px;
+ font-size: 64px;
+ color: #43996E;
+ text-shadow: 0px 2px white, 0px 2px 2px rgba(0, 0, 0, 0.27);
+ border-bottom: dashed 1px rgb(215,215,215);
+}
+.pos .splitbill-screen .order {
+ background: white;
+ padding-bottom:15px;
+ padding-top:15px;
+ margin-left:16px;
+ margin-right:16px;
+ margin-top:16px;
+ margin-bottom:16px;
+ font-size:16px;
+ border-radius: 3px;
+ border: solid 1px rgb(220,220,220);
+ text-align: left;
+ max-width: 500px;
+ -webkit-transform: translate3d(0,0,0);
+}
+.splitbill-screen .order .orderline.selected{
+ background: rgb(110,200,155);
+ color: white;
+ -webkit-transition: background 250ms ease-in-out;
+ -moz-transition: background 250ms ease-in-out;
+ transition: background 250ms ease-in-out;
+ cursor: default;
+}
+.splitbill-screen .order .orderline.partially.selected{
+ background: rgb(136, 214, 176);
+}
+.splitbill-screen .order .orderline.selected .info-list {
+ color: white;
+}
+.splitbill-screen .order .orderline.selected .info-list em{
+ color: white;
+ font-size: 24px;
+ vertical-align: top;
+}
+.paymentmethods {
+ margin: 16px;
+}
+.paymentmethods .button {
+ background: #e2e2e2;
+ line-height: 74px;
+ font-size: 16px;
+ border: solid 1px rgb(202, 202, 202);
+ border-top-width: 0px;
+ cursor: pointer;
+ text-align: center;
+}
+.paymentmethods .button:first-child {
+ border-top-width: 1px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.paymentmethods .button:last-child {
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.paymentmethods .button:active {
+ background: black;
+ border-color: black;
+ color: white;
+}
+.paymentmethod .button.active {
+ background: #6EC89B;
+ color: white;
+ border-color: #6EC89B;
+}
+
+
+
+/* ********* The ActionBarWidget ********* */
+
+.pos .pos-actionbar{
+ height: 105px;
+ background: #f5f5f5; /*#ebebeb;*/
+ border-top: solid 1px #cecece;
+ z-index:900;
+}
+
+.pos .pos-actionbar ul{
+ list-style: none;
+}
+
+.pos .pos-actionbar-button-list{
+ height: 100%;
+ margin: 0px;
+ padding-left:3px;
+ padding-right:3px;
+ overflow:hidden;
+}
+
+.pos .pos-actionbar .button{
+ width: 90px;
+ height: 90px;
+ text-align:center;
+ margin:3px;
+ margin-top:6px;
+ float:left;
+
+ font-size: 14px;
+ font-weight: bold;
+
+ cursor: pointer;
+
+ border: 1px solid #cacaca;
+ border-radius: 3px;
+
+ background: #e2e2e2;
+}
+.pos .pos-actionbar .button .label{
+ margin-top: 37px;
+}
+.pos .pos-actionbar .button .icon{
+ margin-top: 10px;
+}
+.pos .pos-actionbar .button:active{
+ color: white;
+ background: #7f82ac;
+ border: 1px solid #7f82ac;
+
+ -webkit-transition-property: background, border;
+ -webkit-transition-duration: 0.2s;
+ -webkit-transition-timing-function: ease-out;
+}
+
+.pos .pos-actionbar .button.disabled{
+ opacity: 0.5;
+}
+.pos .pos-actionbar .button.disabled:active{
+ border: 1px solid #cacaca;
+ color: #555;
+ cursor: default;
+
+ background: #e2e2e2;
+}
+
+.pos .pos-actionbar .button.rightalign{
+ float:right;
+}
+/* ********* The Debug Widget ********* */
+
+.pos .debug-widget{
+ z-index:100000;
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ width: 200px;
+ font-size: 10px;
+
+ background: rgba(0,0,0,0.82);
+ color: white;
+ padding-bottom: 10px;
+ cursor: move;
+ -webkit-transform: translate3d(0,0,0);
+}
+.pos .debug-widget .toggle{
+ position: absolute;
+ font-size: 16px;
+ cursor:pointer;
+ top:0px;
+ right:0px;
+ padding:10px;
+ padding-right:15px;
+}
+.pos .debug-widget .content{
+ overflow: hidden;
+}
+.pos .debug-widget h1{
+ background:black;
+ padding-top: 10px;
+ padding-left: 10px;
+ margin-top:0;
+ margin-bottom:0;
+}
+.pos .debug-widget .category{
+ background: black;
+ padding-left: 10px;
+ margin: 0px;
+ font-weight: bold;
+ padding-top:3px;
+ padding-bottom:3px;
+}
+.pos .debug-widget .button{
+ padding: 5px;
+ padding-left: 15px;
+ display: block;
+ cursor:pointer;
+}
+.pos .debug-widget .button:active{
+ background: rgba(96,21,177,0.45);
+}
+.pos .debug-widget input{
+ margin-left:10px;
+ margin-top:7px;
+ padding: 4px;
+ width: 180px;
+ border: none;
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ border-radius: 3px;
+}
+.pos .debug-widget .status{
+ padding: 5px;
+ padding-left: 15px;
+ display: block;
+ cursor:default;
+}
+.pos .debug-widget .status.on{
+ background-color: #6cd11d;
+}
+.pos .debug-widget .event{
+ padding: 5px;
+ padding-left: 15px;
+ display: block;
+ cursor:default;
+ background-color: #1E1E1E;
+}
+
+/* ********* The PopupWidgets ********* */
+
+.pos .modal-dialog{
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height:100%;
+ background-color: rgba(0,0,0,0.5);
+ z-index:1000;
+}
+.pos .modal-dialog .popup{
+ position: absolute;
+ top: 0; left: 0; right: 0; bottom: 0;
+ margin: auto;
+ width:500px;
+ height:400px;
+ text-align:center;
+ font-size:20px;
+ font-weight:bold;
+ background-color: #F0EEEE;
+ border-radius: 3px;
+ box-shadow: 0px 10px 20px rgba(0,0,0,0.4);
+ z-index:1200;
+ font-family: 'Lato';
+ font-family: Lato;
+}
+.pos .modal-dialog .popup-confirm{
+ height: 250px;
+}
+.pos .popup-confirm .body {
+ overflow: auto;
+ height: 120px;
+}
+.pos .popup .title {
+ background: rgba(255,255,255,0.5);
+ margin: 0;
+ padding: 20px;
+ border-radius: 3px 3px 0px 0px;
+ border-bottom: solid 1px rgba(60,60,60,0.1);
+}
+.pos .popup .body {
+ font-weight: normal;
+ font-size: 18px;
+ margin: 16px;
+ margin-top: 20px;
+}
+.pos .popup .body.traceback {
+ height: 238px;
+ overflow: auto;
+ font-size: 14px;
+ white-space: pre-wrap;
+ text-align: left;
+ font-family: 'Inconsolata';
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ user-select: text;
+}
+.pos .popup .footer{
+ position:absolute;
+ bottom:0;
+ left:0;
+ width:100%;
+ height:60px;
+ border-top: solid 1px rgba(60,60,60,0.1);
+}
+.pos .popup .button{
+ float:right;
+ width: 110px;
+ height: 40px;
+ line-height:40px;
+ text-align:center;
+ border-radius: 2px;
+ margin-top:10px;
+ margin-right:10px;
+
+ font-size: 14px;
+ font-weight: bold;
+
+ cursor: pointer;
+
+ border: solid 1px rgba(60,60,60,0.1);
+
+ background: rgba(0,0,0,0.05);
+}
+.pos .popup .button.icon {
+ width: 40px;
+ font-size: 20px;
+}
+.pos .popup .button:active{
+ color: white;
+ background: black;
+ border: 1px solid black;
+
+ -webkit-transition-property: background, border;
+ -webkit-transition-duration: 0.2s;
+ -webkit-transition-timing-function: ease-out;
+}
+
+
+.pos .popup .button.big-left{
+ position:absolute;
+ top: 120px;
+ left:40px;
+ width: 180px;
+ height: 180px;
+ line-height:180px;
+}
+
+.pos .popup .button.big-right{
+ position:absolute;
+ top: 120px;
+ right:40px;
+ width: 180px;
+ height: 180px;
+ line-height:180px;
+}
+.pos .popup input,
+.pos .popup-input {
+ text-align: left;
+ display: inline-block;
+ overflow: hidden;
+ background: white;
+ min-height: 44px;
+ font-family: "Lato";
+ font-size: 20px;
+ color: #444;
+ padding: 10px;
+ border-radius: 3px;
+ border: none;
+ box-shadow: 0px 0px 0px 1px rgb(220,220,220) inset;
+ box-sizing: border-box;
+ width: 80%;
+}
+.pos .popup .packlot-lines{
+ overflow: auto;
+ height: 250px;
+ margin: 10px;
+}
+.pos .popup .packlot-line-input {
+ margin: 3px;
+}
+
+.pos .popup-number .popup-input {
+ text-align: center;
+}
+.pos .popup input:focus,
+.pos .popup-input.active {
+ outline: none;
+ box-shadow: 0px 0px 0px 3px #6EC89B;
+}
+.pos .popup.popup-error {
+ background-color: #F3BBBB;
+ color: rgb(168, 89, 89);
+ box-shadow: 0px 10px 20px rgba(92,51,51,0.4);
+}
+.pos .popup.popup-error .title {
+ color: white;
+ background: rgba(255, 76, 76, 0.5);
+}
+.pos .popup.popup-selection .selection {
+ overflow-y: auto;
+ max-height: 273px;
+ font-size: 16px;
+ width: auto;
+ line-height: 50px;
+ margin-top: -1px;
+ border-top: solid 3px rgba(60,60,60,0.1);
+
+}
+.pos .popup.popup-selection .selection-item {
+ width: auto;
+ background: rgb(230,230,230);
+ cursor: pointer;
+ text-align: left;
+ padding: 0px 16px;
+}
+.pos .popup.popup-selection .selection-item:nth-child(odd) {
+ background: rgb(247,247,247);
+}
+.pos .popup.popup-selection .selection-item.selected {
+ background: #6EC89B;
+}
+.pos .popup.popup-number {
+ width: 300px;
+ height: 450px;
+}
+.pos .footer.centered {
+ text-align: center;
+}
+.pos .footer.centered .button {
+ float: none;
+ display: inline-block;
+ margin-left: 3px;
+ margin-right: 3px;
+}
+.pos .popup-numpad {
+ direction: ltr/*rtl:ignore*/; /* rtlcss forced to keep ltr */
+ margin: 12px auto;
+ text-align: center;
+ width: 254px;
+}
+.pos .popup-number .title,
+.pos .popup-textinput .title
+{
+ margin-bottom: 20px;
+}
+.pos .popup-numpad .input-button,
+.pos .popup-numpad .mode-button {
+ background: none;
+ height: 50px;
+ width: 50px;
+ padding: 0;
+ border-radius: 25px;
+ margin: 4px;
+ vertical-align: top;
+ color: #444;
+}
+.pos .popup-numpad .input-button:active,
+.pos .popup-numpad .mode-button:active {
+ background: #444;
+ color: white;
+ border-color: #444;
+}
+
+.pos .popup.popup-password {
+ width: 254px;
+}
+.pos .popup-password .mode-button.add,
+.pos .popup-password .input-button.dot {
+ display: none;
+}
+.pos .popup-password .popup-numpad {
+ width: 190px;
+ text-align: left;
+}
+.pos .popup-password .popup-input {
+ width: 70%;
+ }
+
+.pos .popup .body ul,
+.pos .popup ul.body {
+ text-align: left;
+ margin-left: 1em;
+}
+.pos .popup .body li {
+ text-indent: 1em;
+}
+.pos .popup .body li:before {
+ content: '—';
+ position: relative;
+ font-size: 0.6em;
+ left: -1em;
+ bottom: 0.2em;
+}
+
+
+/* ********* The Webkit Scrollbar ********* */
+
+.pos *::-webkit-scrollbar{
+ width: 4px;
+ height: 4px;
+}
+.pos *::-webkit-scrollbar-track{
+ background: rgb(224,224,224);
+ border-left: solid 1px rgb(200,200,200);
+}
+.pos *::-webkit-scrollbar-thumb{
+ background: rgb(168,168,168);
+ background: #393939;
+ min-height: 30px;
+}
+
+.pos.big-scrollbars *::-webkit-scrollbar{
+ width: 40px;
+ height: 40px;
+}
+.pos.big-scrollbars *::-webkit-scrollbar-track{
+ background: rgb(224,224,224);
+ border-left: none;
+}
+.pos.big-scrollbars *::-webkit-scrollbar-thumb{
+ background: rgb(168,168,168);
+ min-height: 40px;
+ border-radius: 3px;
+}
+.pos.big-scrollbars *::-webkit-scrollbar-button{
+ width: 40px;
+ height: 40px;
+ border-radius: 3px;
+ background: rgb(210,210,210);
+ background-size: cover;
+}
+.pos.big-scrollbars *::-webkit-scrollbar-button:decrement{
+ background-image: url('../img/scroll-up.png');
+}
+.pos.big-scrollbars *::-webkit-scrollbar-button:increment{
+ background-image: url('../img/scroll-down.png');
+}
+
+
+/* ********* Unsupported Browser Page ********* */
+
+.pos .not-supported-browser{
+ position: absolute;
+ z-index: 100000;
+ top: 0; bottom: 0; left: 0; right: 0;
+ background: #2C2C2C;
+}
+.pos .not-supported-browser .message{
+ width:600px;
+ margin-top: 100px;
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+ color: #d3d3d3;
+ font-size: 14px;
+}
+.pos .not-supported-browser img{
+ border-collapse: separate;
+}
+
+/* Open Workshop specific styles */
+.pos {
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+ width: 100%;
+ background: #d3d3d3
+}
+
+.pos .order-selector {
+ position: absolute;
+ top: 48px;
+ left: 0;
+ width: 10%;
+ height: calc(100% - 48px);
+ z-index: 10;
+}
+
+/* Sidebar für Einweisungen*/
+
+.pos .machine-access-sidebar {
+ position: absolute;
+ top: 48px; /* unter der Topbar */
+ bottom: 0;
+ height: calc(100% - 48px);
+ left: 10%; /* Platz für Order-Selector */
+ right: 0;
+ width: 10%;
+ background: #d3d3d3;
+ overflow-y: auto;
+ border-right: 3px solid #787878;
+ z-index: 20;
+}
+
+.pos .machine-access-sidebar .access-content {
+ position: relative;
+ top: 0px; /* unter der Topbar */
+ background : #eeeeee;
+}
+
+.pos .machine-access-sidebar .client-details-label {
+ font-size: 18px;
+ line-height: 48px;
+}
+
+.pos .machine-access-sidebar h5 {
+ margin-top: 1em;
+ margin-bottom: 0.5em;
+}
+
+.pos .machine-access-sidebar ul {
+ padding-left: 1em;
+}
+
+.pos .machine-access-sidebar li {
+ margin-bottom: 0.3em;
+}
+
+.pos .machine-access-sidebar .subpoints {
+ margin-left: 0.5em;
+ list-style-type: none; /* oder none, wenn du keine Punkte willst */
+}
+
+.pos .machine-access-sidebar .client-details-vvow_sec_briefing_error{
+ color: rgb(255, 0, 0);
+}
+
+.pos .clientlist-screen .client-details{
+ padding: 16px;
+ border-bottom: solid 5px rgb(110,200,155);
+}
+.pos .clientlist-screen .client-details-error{
+ padding: 16px;
+ border-bottom: solid 5px rgb(110,200,155);
+ background: rgb(178, 34, 34);
+}
+/* .pos .clientlist-screen .client-details-vvow_briefing{
+ color: rgb(128, 255, 0);
+} */
+.pos .client-details-vvow_briefing_error{
+ color: rgb(255, 0, 0);
+}
+.pos .clientlist-screen .client-details-vvow_sec_briefing_error{
+ color: rgb(255, 0, 0);
+ font-size: xx-large;
+}
\ No newline at end of file
diff --git a/static/src/js/machine_access_sidebar.js b/static/src/js/machine_access_sidebar.js
new file mode 100644
index 0000000..f94cb2b
--- /dev/null
+++ b/static/src/js/machine_access_sidebar.js
@@ -0,0 +1,132 @@
+/* This file is based on the original code from the OrderWidget in Odoo Point of Sale module (screen.js).
+ * It has been modified to create a sidebar that displays machine access information for the selected customer.*/
+
+odoo.define('open_workshop.machine_access_sidebar', function (require) {
+ "use strict";
+
+ const DUMMY_PARTNER = {
+ id: 1,
+ name: "AAAA Max Mustermann",
+ security_briefing: false,
+ security_id: null,
+ create_date: null,
+ };
+
+ var rpc = require('web.rpc');
+ var screens = require('point_of_sale.screens');
+ var chrome = require('point_of_sale.chrome');
+ var core = require('web.core');
+ var QWeb = core.qweb;
+
+
+
+ var MachineAccessSidebar = screens.ScreenWidget.extend({
+ template: 'MachineAccessSidebar',
+
+ init: function(parent, options) {
+ this._super(parent, options);
+ this.partner = null;
+ this.pos.bind('change:selectedOrder', this.bind_order_events, this);
+ },
+
+ show: function() {
+ this._super();
+ this.render_access();
+ },
+
+ update_machine_access: function(partner) {
+ console.log("🔁 Sidebar aktualisiert Maschinenfreigaben für Partner:", partner);
+ this.partner = partner;
+ this.render_access();
+ },
+
+ render_access: function() {
+ var self = this;
+ var partner = this.partner || DUMMY_PARTNER;
+
+
+
+ rpc.query({
+ model: 'ows.machine',
+ method: 'get_access_list_grouped',
+ args: [partner.id],
+ }).then(function (result) {
+ partner.create_date = partner.create_date && partner.create_date.substring(0, 10);
+ var html = QWeb.render('PartnerMachineAccessList', {
+ areas: result || [],
+ partner: partner,
+ });
+ self.$('.access-content').html(html);
+ });
+ },
+
+ bind_order_events: function () {
+ var order = this.pos.get_order();
+ if (!order) return;
+
+ /*order.unbind('change:client', this);
+ order.bind('change:client', this, function () {
+ this.update_machine_access(order.get_client());
+ });*/
+
+ this.update_machine_access(order.get_client());
+ }
+ });
+
+ // Sidebar aktualisieren bei Klick im ClientListScreenWidget (Vorschau)
+ screens.ClientListScreenWidget.include({
+ show: function () {
+ this._super();
+ $('.order-selector').hide(); // ← wird hier versteckt
+ },
+ hide: function () {
+ this._super();
+ $('.order-selector').show(); // ← beim Verlassen wieder zeigen
+ },
+ display_client_details: function (visibility, partner, clickpos) {
+ this._super(visibility, partner, clickpos);
+
+ try {
+ if (partner && typeof partner === 'object' && 'id' in partner) {
+ var sidebar = this.pos.chrome.sidebar_widget;
+ if (sidebar) {
+ console.log("👤 ClientListScreen: Vorschau für", partner.name);
+ sidebar.update_machine_access(partner);
+ }
+ }
+ } catch (e) {
+ console.warn("⚠️ Fehler beim Update der Sidebar nach Kundenauswahl:", e);
+ }
+ }
+ });
+
+ chrome.Chrome.include({
+ build_widgets: function () {
+ this._super();
+
+ var sidebar = new MachineAccessSidebar(this, {});
+ this.sidebar_widget = sidebar;
+ sidebar.appendTo(this.$el);
+
+ //this.pos.bind('change:selectedOrder', sidebar.bind_order_events, sidebar);
+
+ if (this.pos.get_order()) {
+ sidebar.bind_order_events();
+ }
+ }
+ });
+});
+
+
+odoo.define('open_workshop.models', function (require) {
+ "use strict";
+ var models = require('point_of_sale.models');
+ var field_utils = require('web.field_utils');
+ models.load_fields('res.partner', 'create_date');
+ models.load_fields('res.partner', 'birthday');
+ models.load_fields('res.partner', 'security_briefing');
+ models.load_fields('res.partner', 'security_id');
+ models.load_fields('res.partner', 'rfid_card');
+
+
+});
\ No newline at end of file
diff --git a/static/src/xml/ows_briefing_details.xml b/static/src/xml/ows_briefing_details.xml
new file mode 100644
index 0000000..3f056b3
--- /dev/null
+++ b/static/src/xml/ows_briefing_details.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+ Address
+
+
+
+
+
+
+ N/A
+
+
+
+ Email
+
+
+
+
+
+
+ N/A
+
+
+
+
+ Geburtstag
+
+
+
+
+
+
+ N/A
+
+
+
+ Phone
+
+
+
+
+
+
+ N/A
+
+
+
+ Pricelist
+
+
+
+
+
+
+ N/A
+
+
+
+ Haftungsausschluss prüfen!
+
+
+
+
+
+
+
+
diff --git a/static/src/xml/ows_briefing_details_edit.xml b/static/src/xml/ows_briefing_details_edit.xml
new file mode 100644
index 0000000..53c79a6
--- /dev/null
+++ b/static/src/xml/ows_briefing_details_edit.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+ Street
+
+
+
+ Postcode
+
+
+
+ City
+
+
+
+ Country
+
+
+
+ Email
+
+
+
+ Phone
+
+
+
+ Geburtstag
+
+
+
+ Pricelist
+
+
+
+
+ Haftungsauschschluß
+
+
+
+
+
+
+
diff --git a/static/src/xml/ows_machine_sidebar.xml b/static/src/xml/ows_machine_sidebar.xml
new file mode 100644
index 0000000..61f19a2
--- /dev/null
+++ b/static/src/xml/ows_machine_sidebar.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ ❌
+
+
+ ✅
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/src/xml/ows_pos_order_selector.xml b/static/src/xml/ows_pos_order_selector.xml
new file mode 100644
index 0000000..e4956b7
--- /dev/null
+++ b/static/src/xml/ows_pos_order_selector.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ?
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/__init__.py b/tests/__init__.py
index ea197db..d57d215 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,2 +1 @@
from . import test_res_partner
-from . import test_access_rights
diff --git a/tests/test_access_rights.py b/tests/test_access_rights.py
deleted file mode 100644
index 7f91d26..0000000
--- a/tests/test_access_rights.py
+++ /dev/null
@@ -1,74 +0,0 @@
-'''
-/odoo_env/src/odoo/odoo-bin \
- -d hh16-test \
- --data-dir=/env/filestore/ \
- --addons-path=/odoo_env/src/odoo/addons,/odoo_env/src/odoo/odoo/addons,/odoo_env/src/openupgrade,/odoo_env/src/OCA/web,/odoo_env/src/OCA/server-tools,/odoo_env/src/vvow \
- --test-enable \
- --stop-after-init \
- --test-tags open_workshop \
- --log-level=debug \
- --http-port=9070 \
- --db_host=db \
- --db_user=odoo \
- --db_password=odoo
-'''
-
-from odoo.tests.common import TransactionCase
-from odoo.tests import tagged
-import logging
-
-_logger = logging.getLogger(__name__)
-
-@tagged('post_install', 'open_workshop', 'access_rights')
-class TestOpenWorkshopAccessRights(TransactionCase):
-
- def setUp(self):
- super().setUp()
- self.group_user = self.env.ref('base.group_user')
- self.test_user = self.env['res.users'].create({
- 'name': 'Access Test User',
- 'login': 'access_test_user',
- 'groups_id': [(6, 0, [self.group_user.id])],
- })
- self.models_to_test = [
- 'ows.machine',
- 'ows.machine.access',
- 'ows.machine.product',
- 'ows.machine.training',
- 'ows.machine.area',
- 'ows.user',
- ]
-
- def test_model_access_rights(self):
- for model_name in self.models_to_test:
- with self.subTest(model=model_name):
- model = self.env[model_name].with_user(self.test_user)
- records = model.search([], limit=1)
-
- # Test Lesezugriff
- self.assertTrue(records.exists(), f"Kein Zugriff auf {model_name} oder leer")
-
- # Test Schreib-, Erstell- und Löschrechte nur wenn Eintrag existiert
- if records:
- # Schreibtest
- write_fields = [f for f in records._fields if records._fields[f].type in ('char', 'text') and f != 'id']
- if write_fields:
- field = write_fields[0]
- test_value = 'Test Write'
- try:
- records.write({field: test_value})
- except Exception as e:
- self.fail(f"❌ Schreibrechte auf {model_name}.{field} verweigert: {e}")
-
- # Erstellung
- try:
- new = records.copy()
- self.assertTrue(new.exists(), f"❌ Kein Erstellrecht auf {model_name}")
- except Exception as e:
- self.fail(f"❌ Erstellung in {model_name} verweigert: {e}")
-
- # Löschung
- try:
- new.unlink()
- except Exception as e:
- self.fail(f"❌ Löschrechte auf {model_name} verweigert: {e}")
diff --git a/tests/test_res_partner.py b/tests/test_res_partner.py
index 967fe1e..6c88da7 100644
--- a/tests/test_res_partner.py
+++ b/tests/test_res_partner.py
@@ -1,6 +1,8 @@
## Testausführung
-# /odoo_env/src/odoo/odoo-bin -d hh16 --test-enable --stop-after-init --test-tags open_workshop --log-level=debug --update open_workshop --stop-after-init --db_host=db --db_user=odoo --db_password=odoo
-
+# odoo-bin -d deine_testdatenbank --test-enable --init open_workshop
+## oder:
+# /opt/odoo/odoo/odoo-bin -d hobbyhimmel --test-enable --test-tags /test_res_partner.py --stop-after-init --http-port=8070 --log-level=debug
+# /opt/odoo/odoo/odoo-bin -d hobbyhimmel --test-enable --stop-after-init --test-tags open_workshop --log-level=debug --update open_workshop --http-port=8070
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
diff --git a/views/assets.xml b/views/assets.xml
new file mode 100644
index 0000000..81ce2a4
--- /dev/null
+++ b/views/assets.xml
@@ -0,0 +1,9 @@
+
+
diff --git a/views/machine_area_views.xml b/views/machine_area_views.xml
new file mode 100644
index 0000000..88e9956
--- /dev/null
+++ b/views/machine_area_views.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ Maschinenbereiche
+ ows.machine.area
+ tree,form
+
+
+
+
+
+
+
+ ows.machine.area.tree
+ ows.machine.area
+
+
+
+
+
+
+
+
+
+
+ ows.machine.area.form
+ ows.machine.area
+
+
+
+
+
diff --git a/views/machine_product_training_views.xml b/views/machine_product_training_views.xml
new file mode 100644
index 0000000..53a9d60
--- /dev/null
+++ b/views/machine_product_training_views.xml
@@ -0,0 +1,49 @@
+
+
+
+ ows.machine.product.tree
+ ows.machine.product
+
+
+
+
+
+
+
+
+
+
+ ows.machine.training.tree
+ ows.machine.training
+
+
+
+
+
+
+
+
+
+
+ Maschinen-Nutzungsprodukte
+ ows.machine.product
+ tree
+
+
+ Verwalte die Zuordnung von Maschinen zu Nutzungsprodukten.
+
+
+
+
+
+ Maschinen-Einweisungsprodukte
+ ows.machine.training
+ tree
+
+
+ Verwalte die Zuordnung von Maschinen zu Einweisungsprodukten.
+
+
+
+
+
diff --git a/views/machine_views.xml b/views/machine_views.xml
new file mode 100644
index 0000000..0dd3ec6
--- /dev/null
+++ b/views/machine_views.xml
@@ -0,0 +1,55 @@
+
+
+
+
+ ows.machine.tree
+ ows.machine
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ows.machine.form
+ ows.machine
+
+
+
+
+
diff --git a/views/menu_views.xml b/views/menu_views.xml
new file mode 100644
index 0000000..b70287b
--- /dev/null
+++ b/views/menu_views.xml
@@ -0,0 +1,81 @@
+
+
+
+
+ Maschinen
+ ows.machine
+ tree,form
+
+
+
+
+ Einweisungs-Produkte
+ ows.machine.product
+ tree,form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ows.machine.product.tree
+ ows.machine.product
+
+
+
+
+
+
+
+
+
+ ows.machine.product.form
+ ows.machine.product
+
+
+
+
+
diff --git a/views/res_partner_view.xml b/views/res_partner_view.xml
new file mode 100644
index 0000000..ed18541
--- /dev/null
+++ b/views/res_partner_view.xml
@@ -0,0 +1,111 @@
+
+
+
+ res.partner.form.ows.tabs
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ res.partner.form.ows.birthday
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+ res.partner.ows.tree
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ res.partner.form.inherit.default_person
+ res.partner
+
+
+
+ person
+
+
+
+
+
+
+ tree,kanban,form,activity
+
+
+
+
+
+
+
+