165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
# The COPYRIGHT file at the top level of this repository contains the full
|
|
# copyright notices and license terms.
|
|
from functools import wraps
|
|
from decimal import Decimal
|
|
from trytond.model import fields
|
|
from trytond.pyson import Eval
|
|
from trytond.pool import Pool
|
|
from trytond.transaction import Transaction
|
|
from trytond.exceptions import UserError
|
|
from trytond.i18n import gettext
|
|
try:
|
|
from \
|
|
trytond.modules.analytic_account_root_mandatory_bypass.analytic_account \
|
|
import suppress_root_mandatory
|
|
except ModuleNotFoundError:
|
|
def suppress_root_mandatory(func):
|
|
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
class ApplyMethodCostMixin(object):
|
|
__slots__ = ()
|
|
|
|
invoice_party = fields.Many2One('party.party', 'Invoice Party',
|
|
states={
|
|
'invisible': ~Eval('apply_method', '').in_(
|
|
['invoice_in', 'invoice_out'])
|
|
})
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(ApplyMethodCostMixin, cls).__setup__()
|
|
cls.apply_method.selection.append(('invoice_out', 'Invoice Out'))
|
|
cls.apply_method.selection.append(('invoice_in', 'Invoice In'))
|
|
|
|
|
|
class ApplyMethodCostDocumentMixin(ApplyMethodCostMixin):
|
|
__slots__ = ()
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super().__setup__()
|
|
for fieldname in {'formula', 'amount', 'invoice_party'}:
|
|
_field = getattr(cls, fieldname)
|
|
if 'readonly' in _field.states:
|
|
_field.states['readonly'] |= (Eval('invoice_lines', []))
|
|
else:
|
|
_field.states['readonly'] = (Eval('invoice_lines', []))
|
|
|
|
@fields.depends('invoice_lines')
|
|
def get_compute_formula(self, name=None):
|
|
# do not compute amount if invoice lines exist
|
|
return bool(super().get_compute_formula(name) and not self.invoice_lines)
|
|
|
|
@classmethod
|
|
def get_blocked_attributes(cls):
|
|
return super(ApplyMethodCostDocumentMixin,
|
|
cls).get_blocked_attributes() + ['invoice_party']
|
|
|
|
@classmethod
|
|
def _apply_method(cls, apply_method, costs):
|
|
if apply_method in ['invoice_in', 'invoice_out']:
|
|
for cost in costs:
|
|
if cost.amount and not cost.invoice_party:
|
|
raise UserError(gettext(
|
|
'document_cost_apply_invoice.msg_document_cost_apply_invoice_invoice_no_party',
|
|
type_=cost.type_.rec_name,
|
|
cost=cost.rec_name if isinstance(
|
|
cost.document, tuple) else cost.document.rec_name))
|
|
cls.create_invoice_lines(apply_method, costs)
|
|
else:
|
|
super(ApplyMethodCostDocumentMixin, cls)._apply_method(
|
|
apply_method, costs)
|
|
|
|
@classmethod
|
|
def _unapply_method(cls, apply_method, costs):
|
|
InvoiceLine = Pool().get('account.invoice.line')
|
|
with Transaction().set_user(0, set_context=True):
|
|
if apply_method in ['invoice_in', 'invoice_out']:
|
|
lines = InvoiceLine.search([
|
|
('origin.id', 'in', [c.id for c in costs], cls.__name__)])
|
|
for line in lines:
|
|
if line.invoice:
|
|
raise UserError(gettext(
|
|
'document_cost_apply_invoice.msg_document_cost_apply_invoice_unapply_cost',
|
|
origin=line.origin.rec_name,
|
|
invoice=line.invoice.rec_name))
|
|
if lines:
|
|
InvoiceLine.delete(lines)
|
|
else:
|
|
super(ApplyMethodCostDocumentMixin, cls)._unapply_method(
|
|
apply_method, costs)
|
|
|
|
@classmethod
|
|
@suppress_root_mandatory
|
|
def create_invoice_lines(cls, apply_method, costs):
|
|
pool = Pool()
|
|
InvoiceLine = pool.get('account.invoice.line')
|
|
|
|
lines = []
|
|
for cost in costs:
|
|
_lines = cost._get_invoice_lines(apply_method)
|
|
if not _lines:
|
|
continue
|
|
lines.extend(_lines)
|
|
|
|
with Transaction().set_user(0, set_context=True):
|
|
InvoiceLine.save(lines)
|
|
return lines
|
|
|
|
def _get_invoice_lines(self, apply_method):
|
|
pool = Pool()
|
|
InvoiceLine = pool.get('account.invoice.line')
|
|
|
|
if not self.amount or self.invoice_lines:
|
|
return []
|
|
line = InvoiceLine()
|
|
line.type = 'line'
|
|
line.invoice = None
|
|
line.invoice_type = apply_method[8:]
|
|
if isinstance(self.document, tuple):
|
|
line.company = self.company
|
|
line.currency = self.currency
|
|
else:
|
|
line.company = self.document.company
|
|
line.currency = self.document.company.currency
|
|
line.party = self.invoice_party
|
|
if self.type_.product:
|
|
line.product = self.type_.product
|
|
line.unit = self.type_.product.default_uom
|
|
line.on_change_product()
|
|
else:
|
|
line.account = self.type_.account_used
|
|
line.on_change_account()
|
|
|
|
line.origin = self
|
|
line.quantity = self.quantity
|
|
digits = InvoiceLine.unit_price.digits[1]
|
|
line.unit_price = ((self.amount
|
|
/ (Decimal(str(self.quantity)) if self.quantity
|
|
else Decimal('1.0'))
|
|
) * (-1 if line.invoice_type == 'out' else 1)).quantize(
|
|
Decimal(10) ** -Decimal(digits))
|
|
line.amount = line.on_change_with_amount()
|
|
return [line]
|
|
|
|
|
|
class ApplyInvoiceAccountMixin(object):
|
|
__slots__ = ()
|
|
|
|
@classmethod
|
|
def _account_domain(cls):
|
|
InvoiceLine = Pool().get('account.invoice.line')
|
|
res = super()._account_domain()
|
|
return [
|
|
('invoice_out', [
|
|
InvoiceLine._account_domain('out')]),
|
|
('invoice_in', [
|
|
InvoiceLine._account_domain('in')]),
|
|
] + res
|