107 lines
4.2 KiB
Python
107 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Plating product family.
|
|
|
|
import logging
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = 'sale.order'
|
|
|
|
@api.onchange('partner_id')
|
|
def _onchange_partner_id_invoice_strategy(self):
|
|
"""Auto-fill invoice strategy from customer defaults."""
|
|
if self.partner_id:
|
|
default = self.env['fp.invoice.strategy.default'].search(
|
|
[('partner_id', '=', self.partner_id.id)], limit=1,
|
|
)
|
|
if default:
|
|
self.x_fc_invoice_strategy = default.default_strategy
|
|
self.x_fc_deposit_percent = default.default_deposit_percent
|
|
if default.payment_term_id:
|
|
self.payment_term_id = default.payment_term_id
|
|
|
|
def action_confirm(self):
|
|
"""Override to check account hold and trigger invoice strategy."""
|
|
for order in self:
|
|
# --- Account hold check ---
|
|
if order.partner_id.x_fc_account_hold:
|
|
is_manager = self.env.user.has_group(
|
|
'fusion_plating.group_fusion_plating_manager'
|
|
)
|
|
if not is_manager:
|
|
raise UserError(_(
|
|
'Cannot confirm — customer "%s" is on account hold.\n'
|
|
'Reason: %s\n\n'
|
|
'Contact a manager to override.'
|
|
) % (order.partner_id.name,
|
|
order.partner_id.x_fc_account_hold_reason or 'No reason specified'))
|
|
else:
|
|
# Manager gets a warning in chatter but can proceed
|
|
order.message_post(
|
|
body=_(
|
|
'Warning: Customer "%s" is on account hold (reason: %s). '
|
|
'Order confirmed by manager override.'
|
|
) % (order.partner_id.name,
|
|
order.partner_id.x_fc_account_hold_reason or 'N/A'),
|
|
)
|
|
|
|
res = super().action_confirm()
|
|
|
|
# --- Invoice strategy automation ---
|
|
for order in self:
|
|
strategy = order.x_fc_invoice_strategy
|
|
if not strategy:
|
|
continue
|
|
|
|
if strategy == 'deposit' and order.x_fc_deposit_percent:
|
|
order._create_deposit_invoice()
|
|
elif strategy == 'cod_prepay':
|
|
order._create_full_invoice()
|
|
|
|
return res
|
|
|
|
def _create_deposit_invoice(self):
|
|
"""Create a deposit (down payment) invoice for the deposit percentage."""
|
|
self.ensure_one()
|
|
percent = self.x_fc_deposit_percent
|
|
if not percent or percent <= 0:
|
|
return
|
|
|
|
try:
|
|
# Use Odoo's standard down payment mechanism
|
|
wizard = self.env['sale.advance.payment.inv'].create({
|
|
'advance_payment_method': 'percentage',
|
|
'amount': percent,
|
|
})
|
|
wizard.with_context(active_ids=self.ids, active_model='sale.order').create_invoices()
|
|
self.message_post(
|
|
body=_('Deposit invoice (%.0f%%) created automatically — strategy: Deposit.') % percent,
|
|
)
|
|
except Exception as e:
|
|
_logger.warning('Failed to create deposit invoice for SO %s: %s', self.name, e)
|
|
self.message_post(
|
|
body=_('Failed to auto-create deposit invoice: %s. Create manually.') % str(e),
|
|
)
|
|
|
|
def _create_full_invoice(self):
|
|
"""Create a full invoice immediately (COD/Prepay strategy)."""
|
|
self.ensure_one()
|
|
try:
|
|
invoices = self._create_invoices()
|
|
if invoices:
|
|
self.message_post(
|
|
body=_('Full invoice created automatically — strategy: COD / Prepay.'),
|
|
)
|
|
except Exception as e:
|
|
_logger.warning('Failed to create COD invoice for SO %s: %s', self.name, e)
|
|
self.message_post(
|
|
body=_('Failed to auto-create invoice: %s. Create manually.') % str(e),
|
|
)
|