# -*- coding: utf-8 -*- from collections import defaultdict from odoo import models, fields, api, _ from odoo.exceptions import UserError from odoo.tools import float_is_zero, float_compare class PosSession(models.Model): _inherit = 'pos.session' def _accumulate_amounts(self, data): # Call the original method to get all the standard accumulations data = super(PosSession, self)._accumulate_amounts(data) # Get all orders in this session closed_orders = self._get_closed_orders() # If no orders, return original data if not closed_orders: return data # Get the original sales data sales = data.get('sales', {}) if not sales: return data # Create new sales data structure split by payment method split_sales = defaultdict(lambda: {'amount': 0.0, 'amount_converted': 0.0, 'tax_amount': 0.0}) # Get discount product ID from config discount_product_id = self.config_id.discount_product_id.id if self.config_id.discount_product_id else None # For each sale entry, we need to distribute it across payment methods for sale_key, sale_amounts in sales.items(): # Skip if this is a tax key (we only want to split actual sales) if len(sale_key) < 4: # Not a standard sales key continue total_amount = sale_amounts['amount'] total_amount_converted = sale_amounts['amount_converted'] tax_amount = sale_amounts.get('tax_amount', 0.0) # Get tax amount if it exists if float_is_zero(total_amount, precision_rounding=self.currency_id.rounding): continue # Distribute this sales amount across all orders based on their payment methods total_payment_amount = sum(sum(payment.amount for payment in order.payment_ids) for order in closed_orders) if float_is_zero(total_payment_amount, precision_rounding=self.currency_id.rounding): continue # Distribute the sales amount across all orders proportionally to their payments for order in closed_orders: if order.is_invoiced: continue # Skip invoiced orders order_payments = order.payment_ids order_payment_total = sum(payment.amount for payment in order_payments) if float_is_zero(order_payment_total, precision_rounding=order.currency_id.rounding): continue # For each payment in this order, create a split sales entry for payment in order_payments: # Calculate the proportion of this payment relative to all payments payment_proportion = payment.amount / total_payment_amount payment_amount = total_amount * payment_proportion payment_amount_converted = total_amount_converted * payment_proportion payment_tax_amount = tax_amount * payment_proportion if float_is_zero(payment_amount, precision_rounding=self.currency_id.rounding): continue # Determine the account to use based on whether this is a discount product income_account_id = sale_key[0] # default account # Check if this sale key corresponds to a discount product # We need to check if the account in the sale_key matches the discount product account if discount_product_id: # Get the discount product's income account discount_product = self.env['product.product'].browse(discount_product_id) discount_account = discount_product._get_product_accounts()['income'] if discount_account and discount_account.id == sale_key[0]: # This is a discount product, use discount account if configured if payment.payment_method_id.discount_account_id: income_account_id = payment.payment_method_id.discount_account_id.id elif payment.payment_method_id.income_account_id: # This is a regular product, use income account if configured income_account_id = payment.payment_method_id.income_account_id.id # Ensure we have a valid account ID if not income_account_id: continue # Create a new key that includes the payment method new_sale_key = ( # account (use payment method account if specified) income_account_id, # sign (same as original) sale_key[1], # payment method payment.payment_method_id.id, # for taxes (same as original) sale_key[2], # base tags (same as original) sale_key[3], ) # Update the split sales data split_sales[new_sale_key]['amount'] += payment_amount split_sales[new_sale_key]['amount_converted'] += payment_amount_converted split_sales[new_sale_key]['tax_amount'] += payment_tax_amount # Replace the original sales data with our split sales data data['sales'] = split_sales return data def _get_sale_vals(self, key, amount, amount_converted): """ Override to add payment method information to the sales line description """ # Check if this key includes payment method information if len(key) >= 5 and isinstance(key[2], int): # Has payment method ID account_id, sign, payment_method_id, tax_keys, base_tag_ids = key # Try to get the payment method name try: payment_method = self.env['pos.payment.method'].browse(payment_method_id) payment_method_name = payment_method.name except: payment_method_name = "Unknown Payment" else: # Original format account_id, sign, tax_keys, base_tag_ids = key payment_method_name = None tax_ids = set(tax[0] for tax in tax_keys) if tax_keys else set() applied_taxes = self.env['account.tax'].browse(tax_ids) title = _('Sales') if sign == 1 else _('Refund') # Create name with payment method information if payment_method_name: name = _('%s - %s', title, payment_method_name) if applied_taxes: name = _('%s with %s - %s', title, ', '.join([tax.name for tax in applied_taxes]), payment_method_name) else: name = _('%s untaxed', title) if applied_taxes: name = _('%s with %s', title, ', '.join([tax.name for tax in applied_taxes])) partial_vals = { 'name': name, 'account_id': account_id, 'move_id': self.move_id.id, 'tax_ids': [(6, 0, tax_ids)], 'tax_tag_ids': [(6, 0, base_tag_ids)] if base_tag_ids else [], } return self._credit_amounts(partial_vals, amount, amount_converted)