You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
5.4 KiB
125 lines
5.4 KiB
# -*- coding: utf-8 -*-
|
|
################################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
|
|
# Author: Anfas Faisal K (odoo@cybrosys.info)
|
|
#
|
|
# You can modify it under the terms of the GNU AFFERO
|
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
# (AGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
################################################################################
|
|
from odoo import api, models, fields, _
|
|
from odoo.exceptions import UserError
|
|
from odoo.osv.expression import AND
|
|
from odoo.tools import float_round, float_is_zero
|
|
|
|
|
|
class PosOrder(models.Model):
|
|
"""
|
|
This class extends the 'pos.order' model to introduce additional
|
|
functionality related to partial payments and order management in the
|
|
Point of Sale (POS) system.
|
|
|
|
It adds fields and methods for tracking partial payments, computing due
|
|
amounts, and marking orders as paid. The class also includes a method to
|
|
search for partial orders based on specified criteria.
|
|
|
|
"""
|
|
_inherit = 'pos.order'
|
|
|
|
is_partial_payment = fields.Boolean(string="Is Partial Payment",
|
|
default=False,
|
|
help="Flag indicating whether this POS "
|
|
"order is a partial payment.")
|
|
due_amount = fields.Float(string="Amount Due",
|
|
compute='_compute_due_amount',
|
|
store=True,
|
|
help="The amount remaining to be paid for this"
|
|
"POS order.")
|
|
|
|
@api.depends('amount_total', 'amount_paid')
|
|
def _compute_due_amount(self):
|
|
"""
|
|
Compute the due amount for the POS order.
|
|
|
|
This method computes the difference between the total amount and the amount paid
|
|
for the POS order and updates the 'due_amount' field accordingly.
|
|
"""
|
|
for record in self:
|
|
record.due_amount = record.amount_total - record.amount_paid
|
|
|
|
def _order_fields(self, ui_order):
|
|
"""
|
|
Prepare dictionary for create method
|
|
|
|
This method prepares a dictionary of order fields for creating a POS order based
|
|
on the data from the user interface (UI) order.
|
|
"""
|
|
result = super()._order_fields(ui_order)
|
|
result['is_partial_payment'] = ui_order.get('is_partial_payment')
|
|
return result
|
|
|
|
def action_pos_order_paid(self):
|
|
"""
|
|
Mark the POS order as paid. This method marks the POS order as
|
|
paid and ensures that it is fully paid based on the partial
|
|
payment.
|
|
"""
|
|
self.ensure_one()
|
|
# TODO: add support for mix of cash and non-cash payments when both cash_rounding and only_round_cash_method are True
|
|
if not self.config_id.cash_rounding \
|
|
or self.config_id.only_round_cash_method \
|
|
and not any(
|
|
p.payment_method_id.is_cash_count for p in self.payment_ids):
|
|
total = self.amount_total
|
|
else:
|
|
total = float_round(self.amount_total,
|
|
precision_rounding=self.config_id.rounding_method.rounding,
|
|
rounding_method=self.config_id.rounding_method.rounding_method)
|
|
isPaid = float_is_zero(total - self.amount_paid,
|
|
precision_rounding=self.currency_id.rounding)
|
|
if not isPaid:
|
|
pos_config = self.env['pos.config'].search([])
|
|
for shop in pos_config:
|
|
if shop.partial_payment:
|
|
isPaid = True
|
|
if not isPaid and not self.config_id.cash_rounding:
|
|
raise UserError(_("Order %s is not fully paid.", self.name))
|
|
elif not isPaid and self.config_id.cash_rounding:
|
|
currency = self.currency_id
|
|
if self.config_id.rounding_method.rounding_method == "HALF-UP":
|
|
maxDiff = currency.round(
|
|
self.config_id.rounding_method.rounding / 2)
|
|
else:
|
|
maxDiff = currency.round(
|
|
self.config_id.rounding_method.rounding)
|
|
|
|
diff = currency.round(self.amount_total - self.amount_paid)
|
|
if not abs(diff) <= maxDiff:
|
|
raise UserError(_("Order %s is not fully paid.", self.name))
|
|
self.write({'state': 'paid'})
|
|
return True
|
|
|
|
@api.model
|
|
def search_partial_order_ids(self, config_id, domain, limit, offset):
|
|
"""Search for 'partial' orders that satisfy the given domain,
|
|
limit and offset."""
|
|
default_domain = ['&', ('config_id', '=', config_id),
|
|
('is_partial_payment', '=', True), '!', '|',
|
|
('state', '=', 'draft'), ('state', '=', 'cancelled')]
|
|
real_domain = AND([domain, default_domain])
|
|
ids = self.search(AND([domain, default_domain]), limit=limit,
|
|
offset=offset).ids
|
|
totalCount = self.search_count(real_domain)
|
|
return {'ids': ids, 'totalCount': totalCount}
|
|
|