# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import fields, models, api class ResPartner(models.Model): _inherit = 'res.partner' pos_orders_amount_due = fields.Float(string="Sum of customers PoS orders's due amount", compute="_compute_pos_orders_amount_due") invoices_amount_due = fields.Float(string="Sum of customers's invoice due amount", compute="_compute_invoices_amount_due") def _compute_pos_orders_amount_due(self): commercial_partner_ids = {p.id: p.commercial_partner_id.id for p in self} # Fetch the total sum of 'customer_due_total' grouped by 'commercial_partner_id' pos_orders = self.env['pos.order']._read_group( domain=[ ('commercial_partner_id', 'in', set(commercial_partner_ids.values())), ('state', 'in', ['paid', 'done']) ], groupby=['commercial_partner_id'], aggregates=['customer_due_total:sum'] ) due_map = {order[0].id: order[1] for order in pos_orders} for partner in self: partner.pos_orders_amount_due = due_map.get(commercial_partner_ids[partner.id], 0.0) def _compute_invoices_amount_due(self): commercial_partner_ids = {p.id: p.commercial_partner_id.id for p in self} # Fetch the sum of 'pos_amount_unsettled' of unpaid invoices grouped by 'commercial_partner_id' invoices = self.env['account.move']._read_group( domain=[('commercial_partner_id', 'in', set(commercial_partner_ids.values())), ('state', '=', 'posted'), ('payment_state', 'in', ('not_paid', 'partial')), ('move_type', 'in', self.env['account.move'].get_sale_types())], groupby=['commercial_partner_id'], aggregates=['pos_amount_unsettled:sum'] ) due_map = {inv[0].id: inv[1] for inv in invoices} for partner in self: partner.invoices_amount_due = due_map.get(commercial_partner_ids[partner.id], 0.0) def get_total_due(self, config_id): config = self.env['pos.config'].browse(config_id) pos_currency = config.currency_id company_currency = self.env.company.currency_id date = fields.Date.today() pos_payments = self.env['pos.order'].search([ ('commercial_partner_id', '=', self.commercial_partner_id.id), ('state', '=', 'paid'), ('session_id.state', '!=', 'closed')]).mapped('payment_ids') # pos.payment.amount is expressed in the currency of its order, so it is # converted to the PoS currency instead of the company one. total_settled = sum( payment.currency_id._convert(payment.amount, pos_currency, self.env.company, date) for payment in pos_payments.filtered_domain([('payment_method_id.type', '=', 'pay_later')]) ) self_sudo = self group_pos_user = self.env.ref('point_of_sale.group_pos_user') if group_pos_user in self.env.user.all_group_ids: self_sudo = self.sudo() # allow POS users without accounting rights to settle dues # total_due comes from the accounting entries, it is in company currency. total_due = self_sudo.parent_id.total_due if self.parent_id else self_sudo.total_due if company_currency != pos_currency: total_due = company_currency._convert(total_due, pos_currency, self.env.company, date) total_due += total_settled partner = self.env['res.partner']._load_pos_data_read(self, config)[0] partner['total_due'] = total_due return { 'res.partner': [partner], } def get_all_total_due(self, config_id): due_amounts = [] partners = self.exists() for partner in partners: due_amounts.append(partner.get_total_due(config_id)) return due_amounts def get_matching_paylater_orders(self): self.ensure_one() pay_later_refund_orders = self.env["pos.order"].search([ ("commercial_partner_id", "=", self.id), ("state", "in", ["paid", "done"]), ]).filtered( lambda o: ( o.refunded_order_id and any( p.payment_method_id.type == "pay_later" for p in o.payment_ids ) ) ) original_orders = pay_later_refund_orders.mapped("refunded_order_id").filtered(lambda o: o.state in ["paid", "done"]) orders_matched = [] for order in original_orders: refund_orders = pay_later_refund_orders.filtered(lambda o: o.refunded_order_id.id == order.id) original_pay_later_amount = sum(order.payment_ids.filtered(lambda p: p.payment_method_id.type == "pay_later").mapped("amount")) refund_pay_later_amount = sum(refund_orders.mapped("payment_ids").filtered(lambda p: p.payment_method_id.type == "pay_later").mapped("amount")) if order.currency_id.is_zero(original_pay_later_amount + refund_pay_later_amount): orders_matched += order.ids + refund_orders.ids return orders_matched @api.model def _load_pos_data_fields(self, config): params = super()._load_pos_data_fields(config) if self.env.user.has_group('account.group_account_readonly') or self.env.user.has_group('account.group_account_invoice'): params += ['credit_limit', 'total_due', 'use_partner_credit_limit', 'pos_orders_amount_due', 'invoices_amount_due', 'commercial_partner_id'] return params @api.model def _load_pos_data_read(self, records, config): read_records = super()._load_pos_data_read(records, config) if config.currency_id != self.env.company.currency_id and (self.env.user.has_group('account.group_account_readonly') or self.env.user.has_group('account.group_account_invoice')): for record in read_records: record['total_due'] = self.env.company.currency_id._convert(record['total_due'], config.currency_id, self.env.company, fields.Date.today()) return read_records def _compute_has_moves(self): super()._compute_has_moves() for partner in self.filtered(lambda p: not p.has_moves): partner.has_moves = partner.total_due != 0