Kaynağa Gözat

fix(helpdesk): correct hours calc - paid_hours from invoice qty, uninvoiced to credit

odoo 2 ay önce
ebeveyn
işleme
1c50c52c7e

+ 36 - 40
helpdesk_extras/controllers/website_helpdesk_hours.py

@@ -157,59 +157,55 @@ class WebsiteHelpdeskHours(http.Controller):
             prepaid_sol_lines = SaleOrderLine.search(domain)
 
             # NEW LOGIC: Calculate hours based on invoice payment status
-            # - paid_hours: hours from lines with fully PAID invoices
-            # - unpaid_hours: hours from lines with UNPAID/partial invoices
-            # This replaces the old _is_order_paid check
+            # - paid_hours: hours from PAID invoices only (invoice line qty)
+            # - unpaid_invoice_hours: hours from UNPAID invoices
+            # - uninvoiced_hours: hours sold but not yet invoiced
             
             paid_hours = 0.0
-            unpaid_hours = 0.0
+            unpaid_invoice_hours = 0.0
+            uninvoiced_hours = 0.0
             highest_price = 0.0
 
             for line in prepaid_sol_lines:
                 try:
-                    # Get remaining hours for this line
-                    remaining = line.remaining_hours or 0.0
-                    if remaining <= 0:
+                    # Get quantities for this line
+                    qty_sold = line.product_uom_qty or 0.0
+                    qty_invoiced = line.qty_invoiced or 0.0
+                    qty_delivered = line.qty_delivered or 0.0
+                    
+                    if qty_sold <= 0:
                         continue
                     
                     # Track highest price unit
                     if line.price_unit > highest_price:
                         highest_price = line.price_unit
                     
-                    # Check invoice payment status for this line
-                    # A line can have multiple invoice lines, check all of them
+                    # Calculate uninvoiced hours (sold but not yet invoiced)
+                    qty_uninvoiced = max(0.0, qty_sold - qty_invoiced)
+                    uninvoiced_hours += qty_uninvoiced
+                    
+                    # For invoiced portion, check payment status per invoice
                     invoice_lines = line.invoice_lines.sudo()
                     
                     if not invoice_lines:
-                        # No invoices yet - consider as unpaid credit
-                        unpaid_hours += max(0.0, remaining)
+                        # No invoices - all goes to uninvoiced (already counted above)
                         continue
                     
-                    # Get unique invoices for this line
-                    invoices = invoice_lines.mapped('move_id').filtered(
-                        lambda m: m.move_type == 'out_invoice' and m.state == 'posted'
-                    )
-                    
-                    if not invoices:
-                        # No posted invoices - consider as unpaid credit
-                        unpaid_hours += max(0.0, remaining)
-                        continue
-                    
-                    # Check if ALL invoices are paid
-                    # payment_state: 'not_paid', 'partial', 'paid', 'in_payment', 'reversed'
-                    all_paid = all(inv.payment_state == 'paid' for inv in invoices)
-                    any_paid = any(inv.payment_state == 'paid' for inv in invoices)
-                    
-                    if all_paid:
-                        # All invoices paid - hours are available
-                        paid_hours += max(0.0, remaining)
-                    elif any_paid:
-                        # Partial payment - split proportionally
-                        # For simplicity, count as unpaid (conservative approach)
-                        unpaid_hours += max(0.0, remaining)
-                    else:
-                        # No paid invoices - count as credit
-                        unpaid_hours += max(0.0, remaining)
+                    # Process each invoice line
+                    for inv_line in invoice_lines:
+                        inv = inv_line.move_id
+                        # Only count posted customer invoices
+                        if inv.move_type != 'out_invoice' or inv.state != 'posted':
+                            continue
+                        
+                        inv_qty = inv_line.quantity or 0.0
+                        
+                        if inv.payment_state == 'paid':
+                            # Paid invoice - hours are available
+                            paid_hours += inv_qty
+                        else:
+                            # Not paid (not_paid, partial, in_payment, etc.)
+                            unpaid_invoice_hours += inv_qty
                         
                 except Exception as e:
                     _logger.debug(
@@ -286,11 +282,11 @@ class WebsiteHelpdeskHours(http.Controller):
                 if highest_price > 0 and credit_available > 0:
                     credit_from_limit = credit_available / highest_price
 
-            # NEW: Credit hours = unpaid invoice hours + credit limit hours
-            credit_hours = unpaid_hours + credit_from_limit
+            # NEW: Credit hours = uninvoiced hours + unpaid invoice hours + credit limit hours
+            credit_hours = uninvoiced_hours + unpaid_invoice_hours + credit_from_limit
             
-            # Available hours = paid invoice hours only
-            prepaid_hours = paid_hours
+            # Available hours = paid invoice hours only (minus used hours)
+            prepaid_hours = max(0.0, paid_hours - hours_used)
             
             total_available = prepaid_hours + credit_hours