first commit
This commit is contained in:
commit
6801b2e86c
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Editors and IDEs
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.DS_Store
|
||||||
42
README.md
Normal file
42
README.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# POS Edit Payment Method
|
||||||
|
|
||||||
|
An Odoo 19 module designed to allow **POS Managers** to safely edit the payment method used in Point of Sale Orders under specific conditions, while maintaining strict control over other financial fields (like nominal amount and date).
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
- 👤 **Access Limitation**: Only users belonging to the **POS Manager** group (`point_of_sale.group_pos_manager`) can edit the payment method. For standard POS Users, the fields remain completely read-only.
|
||||||
|
- 🔒 **Dynamic Checks & Rules**: Editing is only permitted if:
|
||||||
|
- The POS Session of the order is **not closed**.
|
||||||
|
- The POS Order state is **not Done or Cancelled**.
|
||||||
|
- The order **does not have a posted invoice**.
|
||||||
|
- None of the payments in the order have a **posted accounting journal entry**.
|
||||||
|
- 🚫 **Tamper Prevention**: Other financial fields, such as **amount (nominal)**, **date**, and **card details** are strictly read-only and cannot be manually edited. Standard creation or deletion of payments from the backend list view is disabled (`create="0"` and `delete="0"`).
|
||||||
|
- 💬 **Odoo Chatter Integration**: Seamlessly leverages Odoo's native change tracking system to automatically log changes in the POS Order chatter (e.g., *• BCA changed to BTN for Rp 17,001.00*).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Place the `pos_edit_payment_method` directory inside your custom Odoo addons path.
|
||||||
|
2. Restart your Odoo server instance.
|
||||||
|
3. Log in to your Odoo database as an Administrator.
|
||||||
|
4. Activate **Developer Mode** (Settings -> Activate the developer mode).
|
||||||
|
5. Navigate to the **Apps** menu and click **Update Apps List**.
|
||||||
|
6. Search for `POS Edit Payment Method` in the Apps search bar.
|
||||||
|
7. Click **Activate** (or **Install**).
|
||||||
|
|
||||||
|
## Usage Guide
|
||||||
|
|
||||||
|
1. Go to **Point of Sale** -> **Orders** -> **Orders**.
|
||||||
|
2. Open a POS order whose session is still in progress (not closed).
|
||||||
|
3. Under the **Payments** tab, double-click or inline-edit the **Payment Method** field. Note that other fields (like **Amount** and **Date**) are strictly locked.
|
||||||
|
4. Save the order.
|
||||||
|
5. Review the **Chatter** on the right to see the automatic change log entry.
|
||||||
|
6. Test using an order whose session has already been closed. Verify that the payment method field is locked and cannot be edited.
|
||||||
|
7. Test logging in as a standard POS User (non-manager). Verify that all fields in the payments tab are locked.
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
- **Dependencies**: `point_of_sale`
|
||||||
|
- **Category**: `Point of Sale`
|
||||||
|
- **License**: `LGPL-3`
|
||||||
|
- **Author**: `Suherdy Yacob`
|
||||||
|
- **Version**: `19.0.1.0.0`
|
||||||
1
__init__.py
Normal file
1
__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
19
__manifest__.py
Normal file
19
__manifest__.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
'name': 'POS Edit Payment Method',
|
||||||
|
'version': '19.0.1.0.0',
|
||||||
|
'category': 'Point of Sale',
|
||||||
|
'summary': 'Allows editing the payment method of a POS Order under specific conditions',
|
||||||
|
'description': """
|
||||||
|
This module allows users to edit the payment method used in POS orders:
|
||||||
|
- Only editable if the POS session is not closed and the accounting journal/entry is not posted.
|
||||||
|
- Other payment fields (like amount/nominal) remain strictly read-only.
|
||||||
|
- Log payment method changes in the POS Order's chatter.
|
||||||
|
""",
|
||||||
|
'author': 'Suherdy Yacob',
|
||||||
|
'depends': ['point_of_sale'],
|
||||||
|
'data': [
|
||||||
|
'views/pos_order_views.xml',
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'license': 'LGPL-3',
|
||||||
|
}
|
||||||
2
models/__init__.py
Normal file
2
models/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from . import pos_order
|
||||||
|
from . import pos_payment
|
||||||
33
models/pos_order.py
Normal file
33
models/pos_order.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from odoo import models, fields, api
|
||||||
|
|
||||||
|
class PosOrder(models.Model):
|
||||||
|
_inherit = 'pos.order'
|
||||||
|
|
||||||
|
is_payment_editable = fields.Boolean(
|
||||||
|
compute='_compute_is_payment_editable',
|
||||||
|
string='Is Payment Editable'
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.depends('session_id.state', 'state', 'account_move', 'payment_ids.account_move_id.state')
|
||||||
|
def _compute_is_payment_editable(self):
|
||||||
|
is_manager = self.env.user.has_group('point_of_sale.group_pos_manager')
|
||||||
|
for order in self:
|
||||||
|
# Only POS Managers can edit
|
||||||
|
if not is_manager:
|
||||||
|
order.is_payment_editable = False
|
||||||
|
# 1. POS session must not be closed
|
||||||
|
elif order.session_id.state == 'closed':
|
||||||
|
order.is_payment_editable = False
|
||||||
|
# 2. POS order state must not be done or cancel
|
||||||
|
elif order.state in ('done', 'cancel'):
|
||||||
|
order.is_payment_editable = False
|
||||||
|
# 3. Order must not have a posted invoice
|
||||||
|
elif order.account_move and order.account_move.state == 'posted':
|
||||||
|
order.is_payment_editable = False
|
||||||
|
else:
|
||||||
|
# 4. None of the payments must have a posted accounting journal entry (account_move_id)
|
||||||
|
is_any_payment_posted = any(
|
||||||
|
p.account_move_id and p.account_move_id.state == 'posted'
|
||||||
|
for p in order.payment_ids
|
||||||
|
)
|
||||||
|
order.is_payment_editable = not is_any_payment_posted
|
||||||
23
models/pos_payment.py
Normal file
23
models/pos_payment.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
|
class PosPayment(models.Model):
|
||||||
|
_inherit = 'pos.payment'
|
||||||
|
|
||||||
|
def write(self, vals):
|
||||||
|
if 'payment_method_id' in vals:
|
||||||
|
# Check if current user is not a POS Manager
|
||||||
|
if not self.env.user.has_group('point_of_sale.group_pos_manager'):
|
||||||
|
raise ValidationError(_(
|
||||||
|
"Only POS Managers are allowed to edit payment methods."
|
||||||
|
))
|
||||||
|
|
||||||
|
for payment in self:
|
||||||
|
# Enforce the validation rules
|
||||||
|
if not payment.pos_order_id.is_payment_editable:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"You cannot edit the payment method because the POS session is closed "
|
||||||
|
"or the accounting journal has already been posted."
|
||||||
|
))
|
||||||
|
|
||||||
|
return super(PosPayment, self).write(vals)
|
||||||
59
views/pos_order_views.xml
Normal file
59
views/pos_order_views.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_pos_pos_form_inherit_edit_payment" model="ir.ui.view">
|
||||||
|
<field name="name">pos.order.form.inherit.edit.payment</field>
|
||||||
|
<field name="model">pos.order</field>
|
||||||
|
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<!-- Add is_payment_editable field so the view can evaluate its value -->
|
||||||
|
<xpath expr="//field[@name='partner_id']" position="after">
|
||||||
|
<field name="is_payment_editable" invisible="1"/>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Make payment_ids dynamically editable based on our computed field -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']" position="attributes">
|
||||||
|
<attribute name="readonly">not is_payment_editable</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Inside the list view of payment_ids, make the sub-fields readonly as requested, except payment_method_id -->
|
||||||
|
<!-- Also set create="0" and delete="0" on list to prevent adding or deleting payments manually -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list" position="attributes">
|
||||||
|
<attribute name="create">0</attribute>
|
||||||
|
<attribute name="delete">0</attribute>
|
||||||
|
<attribute name="editable">bottom</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Make date readonly -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='payment_date']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Make payment method editable -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='payment_method_id']" position="attributes">
|
||||||
|
<attribute name="readonly">0</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Make amount/nominal readonly -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='amount']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- Make optional card and mode fields readonly -->
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='payment_method_payment_mode']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='card_no']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='card_brand']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//field[@name='payment_ids']/list/field[@name='cardholder_name']" position="attributes">
|
||||||
|
<attribute name="readonly">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Loading…
Reference in New Issue
Block a user