177 lines
6.8 KiB
Python
177 lines
6.8 KiB
Python
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
# this repository contains the full copyright notices and license terms.
|
|
from trytond.i18n import gettext
|
|
from trytond.model import ModelView, Workflow, fields
|
|
from trytond.pyson import Eval, Bool
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool, PoolMeta
|
|
|
|
from trytond.modules.product import price_digits, round_price
|
|
from .exceptions import InvoiceShipmentCostError
|
|
|
|
|
|
class ShipmentOut(metaclass=PoolMeta):
|
|
__name__ = 'stock.shipment.out'
|
|
|
|
cost_sale_currency_used = fields.Function(fields.Many2One(
|
|
'currency.currency', "Cost Sale Currency",
|
|
states={
|
|
'invisible': Eval('cost_edit', False),
|
|
},
|
|
depends=['cost_edit']),
|
|
'on_change_with_cost_sale_currency_used')
|
|
cost_sale_currency = fields.Many2One(
|
|
'currency.currency', "Cost Sale Currency",
|
|
states={
|
|
'invisible': ~Eval('cost_edit', False),
|
|
'required': Bool(Eval('cost_sale')),
|
|
'readonly': Eval('state').in_(['done', 'cancelled']),
|
|
}, depends=['cost_sale', 'state'])
|
|
cost_sale_used = fields.Function(fields.Numeric(
|
|
"Cost Sale", digits=price_digits,
|
|
states={
|
|
'invisible': Eval('cost_edit', False),
|
|
},
|
|
depends=['cost_edit']),
|
|
'on_change_with_cost_sale_used')
|
|
cost_sale = fields.Numeric(
|
|
"Cost Sale", digits=price_digits,
|
|
states={
|
|
'invisible': ~Eval('cost_edit', False),
|
|
'readonly': ~Eval('state').in_(['done', 'cancelled']),
|
|
}, depends=['state'])
|
|
|
|
cost_invoice_line = fields.Many2One('account.invoice.line',
|
|
'Cost Invoice Line', readonly=True)
|
|
|
|
@classmethod
|
|
def __register__(cls, module):
|
|
table_h = cls.__table_handler__(module)
|
|
# Migration from 5.8: rename cost into cost_sale
|
|
if (table_h.column_exist('cost')
|
|
and not table_h.column_exist('cost_sale')):
|
|
table_h.column_rename('cost', 'cost_sale')
|
|
if (table_h.column_exist('cost_currency')
|
|
and not table_h.column_exist('cost_sale_currency')):
|
|
table_h.column_rename('cost_currency', 'cost_sale_currency')
|
|
super().__register__(module)
|
|
|
|
@fields.depends('carrier', 'company', methods=['_get_carrier_context'])
|
|
def _compute_costs(self):
|
|
costs = super()._compute_costs()
|
|
costs.update({
|
|
'cost_sale': None,
|
|
'cost_sale_currency': None,
|
|
})
|
|
if self.carrier:
|
|
with Transaction().set_context(self._get_carrier_context()):
|
|
cost_sale, sale_currency_id = self.carrier.get_sale_price()
|
|
if cost_sale is not None:
|
|
costs['cost_sale'] = round_price(cost_sale)
|
|
costs['cost_sale_currency'] = sale_currency_id
|
|
return costs
|
|
|
|
@fields.depends(
|
|
'state', 'cost_sale', 'cost_edit', methods=['_compute_costs'])
|
|
def on_change_with_cost_sale_used(self, name=None):
|
|
if not self.cost_edit and self.state not in {'cancelled', 'done'}:
|
|
return self._compute_costs()['cost_sale']
|
|
else:
|
|
return self.cost_sale
|
|
|
|
@fields.depends(
|
|
'state', 'cost_sale_currency', 'cost_edit', methods=['_compute_costs'])
|
|
def on_change_with_cost_sale_currency_used(self, name=None):
|
|
if not self.cost_edit and self.state not in {'cancelled', 'done'}:
|
|
return self._compute_costs()['cost_sale_currency']
|
|
elif self.cost_sale_currency:
|
|
return self.cost_sale_currency.id
|
|
|
|
@fields.depends('cost_edit', 'cost_sale_used', 'cost_sale_currency_used')
|
|
def on_change_cost_edit(self):
|
|
super().on_change_cost_edit()
|
|
if self.cost_edit:
|
|
self.cost_sale = self.cost_sale_used
|
|
self.cost_sale_currency = self.cost_sale_currency_used
|
|
|
|
def _get_cost_tax_rule_pattern(self):
|
|
'Get tax rule pattern for invoice line'
|
|
return {}
|
|
|
|
def get_cost_invoice_line(self, invoice):
|
|
pool = Pool()
|
|
Currency = pool.get('currency.currency')
|
|
InvoiceLine = pool.get('account.invoice.line')
|
|
|
|
if not self.cost_sale_used:
|
|
return
|
|
product = self.carrier.carrier_product
|
|
|
|
invoice_line = InvoiceLine(invoice=invoice)
|
|
invoice_line.on_change_invoice()
|
|
invoice_line.type = 'line'
|
|
invoice_line.quantity = 1 # XXX
|
|
invoice_line.unit = product.sale_uom.id
|
|
cost = self.cost_sale_used
|
|
if invoice.currency != self.cost_sale_currency_used:
|
|
with Transaction().set_context(date=invoice.currency_date):
|
|
cost = Currency.compute(
|
|
self.cost_sale_currency_used, cost,
|
|
invoice.currency, round=False)
|
|
invoice_line.unit_price = round_price(cost)
|
|
invoice_line.product = product
|
|
invoice_line.on_change_product()
|
|
|
|
if not invoice_line.account:
|
|
raise InvoiceShipmentCostError(
|
|
gettext('sale_shipment_cost'
|
|
'.msg_shipment_cost_invoice_missing_account_revenue',
|
|
shipment=self.rec_name,
|
|
product=product.rec_name))
|
|
return invoice_line
|
|
|
|
def _get_shipment_cost(self):
|
|
pool = Pool()
|
|
Currency = pool.get('currency.currency')
|
|
cost = super()._get_shipment_cost()
|
|
methods = {
|
|
m.sale.shipment_cost_method for m in self.outgoing_moves if m.sale}
|
|
if 'shipment' in methods:
|
|
if self.cost_sale:
|
|
cost_sale = Currency.compute(
|
|
self.cost_sale_currency, self.cost_sale,
|
|
self.company.currency, round=False)
|
|
cost -= cost_sale
|
|
if 'order' in methods:
|
|
sales = {
|
|
m.sale for m in self.outgoing_moves
|
|
if m.sale and m.sale.shipment_cost_method == 'order'}
|
|
for sale in sales:
|
|
shipment_cost = sum(
|
|
(s.cost_used or 0) for s in sale.shipments
|
|
if s.state == 'done' and s != self)
|
|
cost_sale = sale.shipment_cost_amount
|
|
cost -= max(cost_sale - shipment_cost, 0)
|
|
return cost
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('done')
|
|
def done(cls, shipments):
|
|
for shipment in shipments:
|
|
shipment.cost_sale = shipment.cost_sale_used
|
|
shipment.cost_sale_currency = shipment.cost_sale_currency_used
|
|
cls.save(shipments)
|
|
super().done(shipments)
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('cancelled')
|
|
def cancel(cls, shipments):
|
|
for shipment in shipments:
|
|
shipment.cost = None
|
|
shipment.cost_sale = None
|
|
shipment.cost_sale_currency = None
|
|
cls.save(shipments)
|
|
super().cancel(shipments)
|