trytondo-optical_equipment/sale.py

254 lines
8.9 KiB
Python

from trytond.pool import Pool, PoolMeta
from trytond.model import ModelView, ModelSQL, fields
from trytond.modules.currency.fields import Monetary
from trytond.pyson import Eval, Bool, If, Get
from decimal import Decimal
from trytond.modules.product import price_digits
from trytond.transaction import Transaction
from trytond.model import Workflow
from trytond.modules.company.model import (
employee_field, set_employee, reset_employee)
from trytond.exceptions import UserError
from trytond.wizard import (
Button, StateAction, StateTransition, StateView, Wizard)
class Sale(metaclass=PoolMeta):
'Sale'
__name__ = 'sale.sale'
agended = fields.Boolean("Scheduling")
sale_type = fields.Selection([('maintenance', 'Maintenance'),
('equipments', 'Equipos'),
('replaces', 'Replaces')], "Sale Type", required=True)
@classmethod
@ModelView.button
@Workflow.transition('confirmed')
@set_employee('confirmed_by')
def confirm(cls, sales):
pool = Pool()
Configuration = pool.get('sale.configuration')
transaction = Transaction()
context = transaction.context
cls.set_sale_date(sales)
cls.store_cache(sales)
config = Configuration(1)
MaintenanceService = pool.get('optical_equipment.maintenance.service')
for sale in sales:
for line in sale.lines:
maintenanceService = MaintenanceService(
maintenance_type='preventive',
state_agended='no_agenda',
propietary=sale.party,
propietary_address=sale.shipment_address,
sale_origin=line,
sale_date=sale.sale_date,
state="draft"
)
maintenanceService.save()
cls.agended = True
sale.save()
with transaction.set_context(
queue_scheduled_at=config.sale_process_after,
queue_batch=context.get('queue_batch', True)):
cls.__queue__.process(sales)
class SaleLine(metaclass=PoolMeta):
'SaleLine'
__name__ = 'sale.line'
product_equipment = fields.Boolean("Product Equipment")
equipment = fields.Many2One('optical_equipment.equipment', "Equipment",
domain=[('state', '=', 'registred'),
('product','=', Eval('product'))
],
states={'invisible': If(~Eval('product_equipment'), True)},)
equipment_serial = fields.Char('Serial',states={'readonly': True,
'invisible': If(~Eval('product_equipment'), True)},
depends=['product_equipment'])
address_equipment = fields.Many2One('party.address', "Direccion")
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits')
@classmethod
def __setup__(cls):
super(SaleLine, cls).__setup__()
cls.quantity.states['readonly'] = If(Eval('product_equipment') == True, True)
#raise UserError(str(Eval('_parent_sale', {}).get('sale_type')))
if Eval('_parent_sale', {}).get('sale_type') == 'maintenance':
cls.product.domain + [('type', '=', 'service'),
('maintenance_activity', '=', True)]
@fields.depends('product_equipment','equipment')
def get_serial_equipment(self):
if self.product_equipment:
return self.equipment.serial
else:
return None
def on_change_with_unit_digits(self, name=None):
if self.unit:
return self.unit.digits
return 2
@fields.depends('equipment', 'sale', 'quantity', '_parent_sale.shipment_address', methods=['on_change_product'])
def on_change_equipment(self):
if self.equipment:
self.product = self.equipment.product.id
self.address_equipment = self.sale.shipment_address.id
self.equipment_serial = self.equipment.serial
self.quantity = 1
self.on_change_product()
else:
self.address_equipment = None
self.product = None
self.unit= None
self.quantity = None
self.unit_price = None
self.amount = None
self.equipment_serial = None
self.on_change_product()
@fields.depends('product_equipment', 'quantity', methods=['on_change_equipment'])
def on_change_product_equipment(self):
if self.product_equipment == False:
self.equipment = None
self.on_change_equipment()
else:
self.quantity = 1
@fields.depends('product', 'unit', 'quantity', 'sale',
'_parent_sale.party',methods=['_get_tax_rule_pattern',
'_get_context_sale_price','on_change_with_amount'])
def on_change_product(self):
Product = Pool().get('product.product')
if not self.product:
self.product_equipment = False
self.unit = None
return
else:
party = None
if self.sale and self.sale.party:
self.product_equipment = False
party = self.sale.party
# Set taxes before unit_price to have taxes in context of sale price
taxes = []
pattern = self._get_tax_rule_pattern()
for tax in self.product.customer_taxes_used:
if party and party.customer_tax_rule:
tax_ids = party.customer_tax_rule.apply(tax, pattern)
if tax_ids:
taxes.extend(tax_ids)
continue
taxes.append(tax.id)
if party and party.customer_tax_rule:
tax_ids = party.customer_tax_rule.apply(None, pattern)
if tax_ids:
taxes.extend(tax_ids)
self.taxes = taxes
category = self.product.sale_uom.category
if not self.unit or self.unit.category != category:
self.unit = self.product.sale_uom
self.unit_digits = self.product.sale_uom.digits
with Transaction().set_context(self._get_context_sale_price()):
self.unit_price = Product.get_sale_price([self.product],
self.quantity or 0)[self.product.id]
if self.unit_price:
self.unit_price = self.unit_price.quantize(
Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
self.type = 'line'
self.amount = self.on_change_with_amount()
if self.product.equipment:
self.product_equipment = True
def get_move(self, shipment_type):
'''
Return moves for the sale line according to shipment_type
'''
pool = Pool()
Move = pool.get('stock.move')
if self.type != 'line':
return
if not self.product:
return
if self.product.type not in Move.get_product_types():
return
if (shipment_type == 'out') != (self.quantity >= 0):
return
quantity = (self._get_move_quantity(shipment_type)
- self._get_shipped_quantity(shipment_type))
quantity = self.unit.round(quantity)
if quantity <= 0:
return
if not self.sale.party.customer_location:
raise PartyLocationError(
gettext('sale.msg_sale_customer_location_required',
sale=self.sale.rec_name,
party=self.sale.party.rec_name))
move = Move()
move.quantity = quantity
move.uom = self.unit
move.product = self.product
move.from_location = self.from_location
move.to_location = self.to_location
move.state = 'draft'
move.company = self.sale.company
move.serial = self.equipment_serial
if move.on_change_with_unit_price_required():
move.unit_price = self.unit_price
move.currency = self.sale.currency
move.planned_date = self.planned_shipping_date
move.invoice_lines = self._get_move_invoice_lines(shipment_type)
move.origin = self
return move
@classmethod
@ModelView.button
def process(cls, sales):
states = {'confirmed', 'processing', 'done'}
sales = [s for s in sales if s.state in states]
cls.lock(sales)
cls._process_invoice(sales)
cls._process_shipment(sales)
cls._process_invoice_shipment_states(sales)
cls._process_state(sales)
@classmethod
def view_attributes(cls):
return super(SaleLine, cls).view_attributes() + [
('//page[@id="equipment"]', 'states', {
'invisible': ~Eval('product_equipment', True),
})]