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' sale_type = fields.Selection([('maintenance', 'Maintenance'), ('equipments', 'Equipments'), ('replaces', 'Replaces')], "Sale Type", required=True, states={'readonly': Eval('state') != 'draft'} ) contract_base = fields.Many2One('optical_equipment.contract', "Contract Base", states={'invisible': (Eval('sale_type') != 'maintenance')}, search_context={ 'related_party': Eval('party'), },) agended = fields.Boolean("Scheduling",states={ 'invisible': (Eval('sale_type') != 'maintenance'), 'readonly': True}) def on_chage_sale_type(self): self.lines= [] @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: if sale.sale_type == 'maintenance': for line in sale.lines: maintenanceService = MaintenanceService( maintenance_type='preventive', state_agended='no_agenda', propietary=sale.party, propietary_address=sale.shipment_address, #contract_origin=sale.contract_base, 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)},) unit_digits = fields.Function(fields.Integer('Unit Digits'), 'on_change_with_unit_digits') @classmethod def __setup__(cls): super(SaleLine, cls).__setup__() cls.product.domain.append( If(Eval('_parent_sale.sale_type') == 'maintenance', [('type', '=', 'service'), ('maintenance_activity', '=', True)], [])) cls.quantity.states['readonly'] = Eval('_parent_sale.sale_type') == 'equipments' def on_change_with_unit_digits(self, name=None): if self.unit: return self.unit.digits return 2 @fields.depends('product', 'unit', 'quantity', 'sale', '_parent_sale.party', '_parent_sale.sale_type', 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 self.quantity = None return else: party = None if self.sale.sale_type == 'equipments': self.quantity = 1 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