trytond-document_cost_apply.../cost.py

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