refactor: centralize payment authorization logic in PoS store and update UI components

This commit is contained in:
Suherdy Yacob 2026-05-12 15:52:29 +07:00
parent 5d13d172ad
commit 6cf02ba859
8 changed files with 61 additions and 66 deletions

View File

@ -1,19 +1,10 @@
from odoo import models, fields from odoo import models, fields, api
class PosOrder(models.Model): class PosOrder(models.Model):
_inherit = 'pos.order' _inherit = 'pos.order'
creator_id = fields.Many2one('hr.employee', string='Order Taker', help='Employee who took the order')
payer_id = fields.Many2one('hr.employee', string='Cashier', help='Employee who processed the payment') payer_id = fields.Many2one('hr.employee', string='Cashier', help='Employee who processed the payment')
employee_id = fields.Many2one('hr.employee', string='Cash Open by', help='Employee who opened the cash register')
def _export_for_ui(self, order): # Existing Odoo/POS fields renamed for clarity
result = super()._export_for_ui(order) user_id = fields.Many2one('res.users', string='Order Taker', help='Odoo user who opened the session')
result['creator_id'] = order.creator_id.id employee_id = fields.Many2one('hr.employee', string='Order Taker', help='Employee who uses the cash register')
result['payer_id'] = order.payer_id.id
return result
def _get_fields_for_draft_order(self):
fields = super()._get_fields_for_draft_order()
fields.extend(['creator_id', 'payer_id'])
return fields

View File

@ -1,16 +0,0 @@
import { patch } from "@web/core/utils/patch";
import { PosOrder } from "@point_of_sale/app/models/pos_order";
patch(PosOrder.prototype, {
setup(vals) {
super.setup(...arguments);
this.creator_id = vals.creator_id || false;
this.payer_id = vals.payer_id || false;
},
serializeForORM() {
const result = super.serializeForORM(...arguments);
result.creator_id = this.creator_id;
result.payer_id = this.payer_id;
return result;
},
});

View File

@ -1,15 +0,0 @@
import { ActionpadWidget } from "@point_of_sale/app/screens/product_screen/action_pad/action_pad";
import { patch } from "@web/core/utils/patch";
patch(ActionpadWidget.prototype, {
async onClickPay() {
if (this.currentOrder.lines.length === 0) {
return;
}
const cashier = this.pos.getCashier();
if (cashier) {
this.currentOrder.payer_id = cashier.id;
}
await this.pos.pay();
}
});

View File

@ -2,14 +2,12 @@
<templates id="template" xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-name="pos_custom_access.ActionpadWidget" t-inherit="point_of_sale.ActionpadWidget" t-inherit-mode="extension"> <t t-name="pos_custom_access.ActionpadWidget" t-inherit="point_of_sale.ActionpadWidget" t-inherit-mode="extension">
<xpath expr="//button[hasclass('pay-order-button')]" position="attributes"> <xpath expr="//button[hasclass('pay-order-button')]" position="attributes">
<attribute name="t-on-click">() => this.onClickPay()</attribute>
<attribute name="t-if">pos.canPay</attribute> <attribute name="t-if">pos.canPay</attribute>
</xpath> </xpath>
</t> </t>
<t t-name="pos_custom_access.ProductScreen" t-inherit="point_of_sale.ProductScreen" t-inherit-mode="extension"> <t t-name="pos_custom_access.ProductScreen" t-inherit="point_of_sale.ProductScreen" t-inherit-mode="extension">
<xpath expr="//button[hasclass('pay-button')]" position="attributes"> <xpath expr="//button[hasclass('pay-button')]" position="attributes">
<attribute name="t-on-click">() => this.onClickPay()</attribute>
<attribute name="t-if">!pos.scanning and pos.canPay</attribute> <attribute name="t-if">!pos.scanning and pos.canPay</attribute>
</xpath> </xpath>
</t> </t>

View File

@ -1,15 +0,0 @@
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
import { patch } from "@web/core/utils/patch";
patch(ProductScreen.prototype, {
async onClickPay() {
if (this.currentOrder.lines.length === 0) {
return;
}
const cashier = this.pos.getCashier();
if (cashier) {
this.currentOrder.payer_id = cashier.id;
}
await this.pos.pay();
}
});

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="pos_custom_access.TicketScreen" t-inherit="point_of_sale.TicketScreen" t-inherit-mode="extension">
<xpath expr="//table//tbody//tr//td[t[@t-esc='getCashier(order)']]" position="replace">
<td>
<div class="small text-muted" title="Order Taker">
<i class="fa fa-user-o me-1"/> <t t-esc="getCashier(order)"/>
</div>
<div t-if="order.payer_id" class="fw-bolder" title="Cashier">
<i class="fa fa-money me-1"/> <t t-esc="order.payer_id.name"/>
</div>
<div t-if="!order.payer_id" class="small text-warning">
Unpaid
</div>
</td>
</xpath>
<xpath expr="//div[hasclass('mobileOrderList')]//div[hasclass('order-name')]" position="inside">
<div class="small text-muted">
Taker: <t t-esc="getCashier(order)"/>
</div>
<div t-if="order.payer_id" class="small text-muted">
Cashier: <t t-esc="order.payer_id.name"/>
</div>
</xpath>
</t>
</templates>

View File

@ -20,11 +20,38 @@ patch(PosStore.prototype, {
await super.setTableFromUi(...arguments); await super.setTableFromUi(...arguments);
const order = this.getOrder(); const order = this.getOrder();
if (order && !order.creator_id) { if (order) {
order.creator_id = cashier.id; order.uiState.is_authorized = true;
} }
}, },
async pay() {
if (this.selectedOrder.lines.length === 0) {
return;
}
if (!this.canPay) {
this.notification.add(_t("You do not have permission to process payments."), {
type: "danger",
});
return;
}
if (!this.selectedOrder.uiState.is_authorized) {
const cashier = await this._selectCashierByPin();
if (!cashier) {
return;
}
this.setCashier(cashier);
this.selectedOrder.uiState.is_authorized = true;
}
this.selectedOrder.update({ payer_id: this.getCashier() });
return super.pay();
},
async _selectCashierByPin() { async _selectCashierByPin() {
if (!this.config.module_pos_hr) { if (!this.config.module_pos_hr) {
return this.getCashier(); return this.getCashier();

View File

@ -6,8 +6,7 @@
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> <field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="creator_id"/> <field name="payer_id" readonly="1"/>
<field name="payer_id"/>
</xpath> </xpath>
</field> </field>
</record> </record>