Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions external_repos.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/odoo/enterprise 17.0 website_sale_renting,sale_renting,web_gantt
1 change: 1 addition & 0 deletions tg_pos_splitpayment/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions tg_pos_splitpayment/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "POS Split Payment",
"version": "17.0.1.0.0",
"author": "IT-Projects LLC",
"license": "LGPL-3",
"depends": ["point_of_sale", "pos_restaurant"],
"data": [
"views/res_config_settings_views.xml",
],
"assets": {
"point_of_sale._assets_pos": [
"tg_pos_splitpayment/static/src/**/*",
],
},
"installable": True,
}
3 changes: 3 additions & 0 deletions tg_pos_splitpayment/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import pos_config
from . import res_config_settings
from . import pos_session
6 changes: 6 additions & 0 deletions tg_pos_splitpayment/models/pos_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from odoo import fields, models

class PosConfig(models.Model):
_inherit = "pos.config"

pos_max_split_orders = fields.Integer("Max Orders to Split", default=3)
10 changes: 10 additions & 0 deletions tg_pos_splitpayment/models/pos_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from odoo import models

class PosSession(models.Model):
_inherit = "pos.session"

def _loader_params_pos_config(self):
result = super()._loader_params_pos_config()
if result['search_params'].get('fields'):
result['search_params']['fields'].append('pos_max_split_orders')
return result
6 changes: 6 additions & 0 deletions tg_pos_splitpayment/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from odoo import fields, models

class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

pos_max_split_orders = fields.Integer(related="pos_config_id.pos_max_split_orders", readonly=False)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/** @odoo-module */

import { usePos } from "@point_of_sale/app/store/pos_hook";
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
import { Component } from "@odoo/owl";
import { SplitPaymentPopup } from "../popups/split_payment_popup/split_payment_popup";
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";

export class SplitPaymentButton extends Component {
static template = "tg_pos_splitpayment.SplitPaymentButton";

setup() {
this.pos = usePos();
}
_isDisabled() {
const order = this.pos.get_order();
return !order || order.get_orderlines().length === 0;
}
async click() {
const order = this.pos.get_order();
if (this._isDisabled()) {
this.env.services.popup.add(ErrorPopup, {
title: "Empty Order",
body: "There are no products in the order to split.",
});
return;
}
const { confirmed, payload: splitParts } = await this.env.services.popup.add(SplitPaymentPopup);
if (confirmed) {
this.pos.showScreen("SplitPaymentScreen", {
order: order,
splitParts: splitParts,
});
}
}
}

ProductScreen.addControlButton({
component: SplitPaymentButton,
condition: function () {
return true;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="tg_pos_splitpayment.SplitPaymentButton">
<span class="control-button order-split btn btn-light rounded-0 fw-bolder" t-att-class="{'disabled': _isDisabled()}" t-on-click="() => this.click()">
<i class="fa fa-scissors me-1"></i>
<span> </span>
<span>Split</span>
</span>
</t>
</templates>
19 changes: 19 additions & 0 deletions tg_pos_splitpayment/static/src/app/navbar/navbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @odoo-module */

import { Navbar } from "@point_of_sale/app/navbar/navbar";
import { patch } from "@web/core/utils/patch";
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";
import { _t } from "@web/core/l10n/translation";

patch(Navbar.prototype, {
async closeSession() {
if (this.pos.orders.some(o => o.tgSplitGroupId && !o.finalized)) {
await this.popup.add(ErrorPopup, {
title: _t("Cannot Close Session"),
body: _t("You cannot close a PoS session until all the split orders are paid."),
});
return;
}
return super.closeSession(...arguments);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/** @odoo-module */

import { AbstractAwaitablePopup } from "@point_of_sale/app/popup/abstract_awaitable_popup";
import { _t } from "@web/core/l10n/translation";
import { usePos } from "@point_of_sale/app/store/pos_hook";
import { useState } from "@odoo/owl";

export class SplitPaymentPopup extends AbstractAwaitablePopup {
static template = "tg_pos_splitpayment.SplitPaymentPopup";
static defaultProps = {
title: _t("Split Payment"),
};

setup() {
super.setup();
this.pos = usePos();
this.maxSplit = this.pos.config.pos_max_split_orders || 3;
this.state = useState({
splitParts: 3 > this.maxSplit ? this.maxSplit : 3,
errorMessage: "",
});
}

getPayload() {
return this.state.splitParts;
}

confirm() {
if (this.state.splitParts < 2) {
this.state.errorMessage = _t("Minimum 2 orders required.");
return;
}
if (this.state.splitParts > this.maxSplit) {
this.state.errorMessage = _t(`Maximum allowed is ${this.maxSplit}.`);
return;
}
this.state.errorMessage = "";
super.confirm();
}

increment() {
if (this.state.splitParts < this.maxSplit) {
this.state.splitParts++;
}
}

decrement() {
if (this.state.splitParts > 2) {
this.state.splitParts--;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="tg_pos_splitpayment.SplitPaymentPopup" owl="1">
<div class="popup popup-number">
<div class="modal-header">
<h4 class="modal-title title" t-esc="props.title" />
</div>
<main class="modal-body body text-center">
<p>How many orders to split into?</p>
<div class="d-flex justify-content-center align-items-center my-4">
<button class="btn btn-secondary fs-1 px-4 py-2" t-on-click="decrement">-</button>
<span class="fs-1 mx-4 fw-bolder" t-esc="state.splitParts"/>
<button class="btn btn-secondary fs-1 px-4 py-2" t-on-click="increment">+</button>
</div>
<div t-if="state.errorMessage" class="text-danger mt-2" t-esc="state.errorMessage" />
</main>
<footer class="footer modal-footer">
<div class="button confirm btn btn-lg btn-primary" t-on-click="confirm">
Ok
</div>
<div class="button cancel btn btn-lg btn-secondary" t-on-click="cancel">
Cancel
</div>
</footer>
</div>
</t>
</templates>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** @odoo-module */

import { PaymentScreen } from "@point_of_sale/app/screens/payment_screen/payment_screen";
import { patch } from "@web/core/utils/patch";

patch(PaymentScreen.prototype, {
async _finalizeValidation() {
// Mark the split group as paid
const splitGroupId = this.currentOrder.tgSplitGroupId;
if (splitGroupId) {
this.pos.orders.forEach(o => {
if (o.tgSplitGroupId === splitGroupId) {
o.isSplitGroupPaid = true;
}
});
}
await super._finalizeValidation(...arguments);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="tg_pos_splitpayment.PaymentScreenTop" t-inherit="point_of_sale.PaymentScreenTop" t-inherit-mode="extension">
<xpath expr="//div[hasclass('button', 'back')]" position="attributes">
<attribute name="t-att-class">{'d-none': currentOrder.tgSplitGroupId and !currentOrder.finalized}</attribute>
</xpath>
</t>
</templates>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/** @odoo-module */

import { ReceiptScreen } from "@point_of_sale/app/screens/receipt_screen/receipt_screen";
import { patch } from "@web/core/utils/patch";
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";
import { _t } from "@web/core/l10n/translation";

patch(ReceiptScreen.prototype, {
async orderDone() {
const splitGroupId = this.currentOrder.tgSplitGroupId;
const nextOrder = splitGroupId ? this.pos.orders.find(o => o.tgSplitGroupId === splitGroupId && !o.finalized && o.uid !== this.currentOrder.uid) : null;

if (nextOrder) {
await this.env.services.popup.add(ErrorPopup, {
title: _t("Cannot Create New Order"),
body: _t("You cannot create a new order until all the split orders are paid."),
});
return;
}
super.orderDone(...arguments);
},
async resumeOrder() {
const splitGroupId = this.currentOrder.tgSplitGroupId;
const nextOrder = splitGroupId ? this.pos.orders.find(o => o.tgSplitGroupId === splitGroupId && !o.finalized && o.uid !== this.currentOrder.uid) : null;
if (nextOrder) {
this.pos.orders.forEach(o => {
if (o.tgSplitGroupId === splitGroupId) {
o.isSplitGroupPaid = true;
}
});

this.pos.removeOrder(this.currentOrder);
this.pos.set_order(nextOrder);
this.pos.resetProductScreenSearch();
this.pos.showScreen("PaymentScreen");
return;
}
return super.resumeOrder(...arguments);
}
});
Loading
Loading