Zahid Anwar
December 6, 2024
First of all create following files inside app directory:
your_app/
├── __init__.py
├── __manifest__.py
├── static/
│ └── src/
│ └── app/
│ └── custom_button/
│ └── custom_button.xml
│ └── custom_button.js
│ └── custom_popup/
│ └── text_input_popup.xml
│ └── text_input_popup.xml
└── README.md
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_custom.ControlButtons" t-inherit="point_of_sale.ControlButtons" t-inherit-mode="extension">
<xpath expr="//button[@class='btn btn-light btn-lg flex-shrink-0 ms-auto']" position="before">
<button class="btn btn-light btn-lg flex-shrink-0 ms-auto"
t-on-click="() => this.onClickPopupSingleField()">Custom Button</button>
</xpath>
<xpath expr="//t[@t-if='props.showRemainingButtons']/div/OrderlineNoteButton" position="after">
<button class="btn btn-secondary btn-lg py-5" t-on-click="() => this.onClickPopupSingleField()">
<i class="fa fa-pencil-square me-1" role="img" aria-label="Custom Alert" title="Custom Alert"/>Custom
Button
</button>
</xpath>
</t>
</templates>
/**@odoo-module **/
import { AlertDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { _t } from "@web/core/l10n/translation";
import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons";
import { patch } from "@web/core/utils/patch";
import { TextInputPopup } from "@pos_custom/app/custom_popup/text_input_popup";
patch(ControlButtons.prototype, {
async onClickPopupSingleField() {
this.dialog.add(TextInputPopup, {
title: _t("To Apply Discount, Enter CNIC & Code"),
placeholder: _t("Enter CNIC"),
getPayload: async (code,code2) => {
let cnic = code.trim();
console.log('Ready to use cnic: ',cnic);
},
});
},
});
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_custom.TextInputPopup">
<Dialog title="props.title">
<t t-foreach="props.buttons" t-as="button" t-key="button_index">
<button t-on-click="() => this.buttonClick(button)" type="button"
t-attf-class="btn btn-lg me-2 mb-2 toggle-button {{button.isSelected? 'btn-primary' : 'btn-secondary'}} lh-lg">
<t t-esc="button.label"/>
</button>
</t>
<textarea t-att-rows="props.rows" class="form-control form-control-lg mx-auto" type="text"
t-model="state.inputValue" t-ref="input" t-att-placeholder="props.placeholder"
t-on-keydown="onKeydown"/>
<t t-set-slot="footer">
<button class="btn btn-primary btn-lg lh-lg o-default-button" t-on-click="confirm">Apply</button>
<button class="btn btn-secondary btn-lg lh-lg o-default-button" t-on-click="close">Discard</button>
</t>
</Dialog>
</t>
</templates>
import { Component, onMounted, useRef, useState } from "@odoo/owl";
import { Dialog } from "@web/core/dialog/dialog";
export class TextInputPopup extends Component {
static template = "pos_custom.TextInputPopup";
static components = { Dialog };
static props = {
title: String,
buttons: { type: Array, optional: true },
startingValue: { type: String, optional: true },
placeholder: { type: String, optional: true },
rows: { type: Number, optional: true },
getPayload: Function,
close: Function,
};
static defaultProps = {
startingValue: "",
placeholder: "",
rows: 1,
buttons: [],
};
setup() {
this.state = useState({ inputValue: this.props.startingValue });
this.inputRef = useRef("input");
onMounted(this.onMounted);
}
onMounted() {
this.inputRef.el.focus();
this.inputRef.el.select();
}
confirm() {
this.props.getPayload(this.state.inputValue);
this.props.close();
}
close() {
this.props.close();
}
buttonClick(button) {
console.log('Button click');
const lines = this.state.inputValue.split("\n").filter((line) => line !== "");
if (lines.includes(button.label)) {
this.state.inputValue = lines.filter((line) => line !== button.label).join("\n");
button.isSelected = false;
} else {
this.state.inputValue = lines.join("\n");
this.state.inputValue += (lines.length > 0 ? "\n" : "") + button.label;
button.isSelected = true;
}
}
onKeydown(ev) {
if (this.props.rows === 1 && ev.key.toUpperCase() === "ENTER") {
this.confirm();
}
}
}
{
'name': 'POS Custom',
'version': '1.0.0',
'category': 'Point of Sale',
'summary': "POS Custom, Odoo18, "
"Odoo Apps",
'description': "Design for better styles",
'author': 'Zahid Anwar',
'company': 'zalino',
'maintainer': 'Nil',
'website': 'https://www.zalinotech.com',
'depends': ['base', 'point_of_sale'],
'assets': {
'point_of_sale._assets_pos': [
'pos_custom/static/src/app/custom_popup/text_input_popup.js',
'pos_custom/static/src/app/custom_popup/text_input_popup.xml',
'pos_custom/static/src/app/custom_button/custom_button.js',
'pos_custom/static/src/app/custom_button/custom_button.xml',
],
},
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False
}
That’s it! You’ve added the custom buttons in point of sale!