shipment equipments

This commit is contained in:
sinergia 2022-08-14 11:16:13 -05:00
parent c4151da4f2
commit 9e73d4ec09
13 changed files with 261 additions and 35 deletions

View File

@ -1,6 +1,6 @@
from trytond.pool import Pool from trytond.pool import Pool
from . import (address, diary, party, product, purchase, sale, from . import (address, diary, party, product, purchase, sale,
equipment, configuration_equipment, maintenance, subscription, exceptions) equipment, configuration_equipment, maintenance, move, subscription, exceptions)
def register(): def register():
Pool.register( Pool.register(
@ -12,6 +12,7 @@ def register():
purchase.Purchase, purchase.Purchase,
purchase.Line, purchase.Line,
sale.Sale, sale.Sale,
sale.SaleLine,
sale.CreateSubscriptionStart, sale.CreateSubscriptionStart,
equipment.OpticalEquipment, equipment.OpticalEquipment,
equipment.EquipmentMaintenance, equipment.EquipmentMaintenance,
@ -19,11 +20,11 @@ def register():
maintenance.Maintenance, maintenance.Maintenance,
maintenance.MaintenanceActivity, maintenance.MaintenanceActivity,
maintenance.MaintenanceLine, maintenance.MaintenanceLine,
move.Move,
move.ShipmentOut,
subscription.Subscription, subscription.Subscription,
subscription.SubscriptionEquipment, subscription.SubscriptionEquipment,
#subscription.CreateContractInvoiceStart,
module='optical_equipment', type_='model') module='optical_equipment', type_='model')
Pool.register( Pool.register(
sale.CreateSubscription, sale.CreateSubscription,
#subscription.CreateContractInvoice,
module='optical_equipment', type_='wizard') module='optical_equipment', type_='wizard')

View File

@ -104,6 +104,10 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
purchase_origin = fields.Reference("Purchase Origin", selection='get_origin',select=True, purchase_origin = fields.Reference("Purchase Origin", selection='get_origin',select=True,
states={'readonly': True}) states={'readonly': True})
sale_destination = fields.Reference("Sale Destination", selection='get_destination',select=True,
states={'readonly': True})
del _states_serial, _states, _depends del _states_serial, _states, _depends
@classmethod @classmethod
@ -129,6 +133,24 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
return [(None, '')] + [(m, get_name(m)) for m in models] return [(None, '')] + [(m, get_name(m)) for m in models]
@classmethod
def _get_destination(cls):
'Return list of Model names for origin Reference'
pool = Pool()
Sale = pool.get('sale.line')
return [Sale.__name__]
@classmethod
def get_destination(cls):
Model = Pool().get('ir.model')
get_name = Model.get_name
models = cls._get_destination()
return [(None, '')] + [(m, get_name(m)) for m in models]
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
@ -142,7 +164,7 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
# 'draft': { # 'draft': {
# 'invisible': Eval('state') == 'draft'}, # 'invisible': Eval('state') == 'draft'},
'registred': { 'registred': {
'invisible': Eval('state').in_(['registred', 'contrated'])}} 'invisible': Eval('state').in_(['registred', 'uncontrated', 'contrated'])}}
) )
@classmethod @classmethod

53
move.py Normal file
View File

@ -0,0 +1,53 @@
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
class Move(metaclass=PoolMeta):
"Stock Move"
__name__ = "stock.move"
serial = fields.Char('Serial')
class ShipmentOut(metaclass=PoolMeta):
"Customer Shipment"
__name__ = 'stock.shipment.out'
def _get_inventory_move(self, move):
'Return inventory move for the outgoing move if necessary'
pool = Pool()
Move = pool.get('stock.move')
Uom = pool.get('product.uom')
quantity = move.quantity
for inventory_move in self.inventory_moves:
if (inventory_move.origin == move
and inventory_move.state != 'cancelled'):
quantity -= Uom.compute_qty(
inventory_move.uom, inventory_move.quantity, move.uom)
quantity = move.uom.round(quantity)
if quantity <= 0:
return
inventory_move = Move(
from_location=self.warehouse_storage,
to_location=move.from_location,
product=move.product,
serial=move.serial,
uom=move.uom,
quantity=quantity,
shipment=self,
planned_date=move.planned_date,
company=move.company,
origin=move,
state='staging' if move.state == 'staging' else 'draft',
)
if inventory_move.on_change_with_unit_price_required():
inventory_move.unit_price = move.unit_price
inventory_move.currency = move.currency
return inventory_move

14
move.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!--This file file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
<tryton>
<record model="ir.ui.view" id="move_view_list_shipment">
<field name="model">stock.move</field>
<field name="inherit" ref="stock.move_view_list_shipment"/>
<field name="name">move_list_shipment</field>
</record>
<record model="ir.ui.view" id="move_view_form">
<field name="model">stock.move</field>
<field name="inherit" ref="stock.move_view_form"/>
<field name="name">move_form</field>
</record>
</tryton>

148
sale.py
View File

@ -1,7 +1,7 @@
from trytond.pool import Pool, PoolMeta from trytond.pool import Pool, PoolMeta
from trytond.model import ModelView, ModelSQL, fields from trytond.model import ModelView, ModelSQL, fields
from trytond.modules.currency.fields import Monetary from trytond.modules.currency.fields import Monetary
from trytond.pyson import Eval, Bool, If from trytond.pyson import Eval, Bool, If, Get
from decimal import Decimal from decimal import Decimal
from trytond.modules.product import price_digits from trytond.modules.product import price_digits
from trytond.transaction import Transaction from trytond.transaction import Transaction
@ -18,6 +18,7 @@ class Sale(metaclass=PoolMeta):
'Sale' 'Sale'
__name__ = 'sale.sale' __name__ = 'sale.sale'
@classmethod @classmethod
@ModelView.button @ModelView.button
@Workflow.transition('confirmed') @Workflow.transition('confirmed')
@ -39,13 +40,24 @@ class Sale(metaclass=PoolMeta):
equipment.propietary=sale.party.id equipment.propietary=sale.party.id
equipment.propietary_address=sale.shipment_address.id equipment.propietary_address=sale.shipment_address.id
equipment.state="uncontrated" equipment.state="uncontrated"
equipment.sale_destination = line
equipment.maintenance_frequency = "6" if sale.party.client_type == "ips" else "12"
equipment.save() equipment.save()
with Transaction().set_context( with Transaction().set_context(
queue_name='sale', queue_name='sale',
queue_scheduled_at=config.sale_process_after): queue_scheduled_at=config.sale_process_after):
cls.__queue__.process(sales) cls.__queue__.process(sales)
# @classmethod
# def get_equipments_in_lines(self, sales, equipments):
# #raise UserError(str(equipments))
# equipments = []
# for line in sales[0].lines:
# if line.product_equipment:
# equipments.append(line.equipment.id)
# return equipments
class SaleLine(metaclass=PoolMeta): class SaleLine(metaclass=PoolMeta):
'SaleLine' 'SaleLine'
@ -56,9 +68,21 @@ class SaleLine(metaclass=PoolMeta):
domain=[('state', '=', 'registred'), domain=[('state', '=', 'registred'),
('product','=', Eval('product'))], ('product','=', Eval('product'))],
states={'invisible': If(~Eval('product_equipment'), True)},) 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") address_equipment = fields.Many2One('party.address', "Direccion")
unit_digits = fields.Function(fields.Integer('Unit Digits'), unit_digits = fields.Function(fields.Integer('Unit Digits'),
'on_change_with_unit_digits') 'on_change_with_unit_digits')
@fields.depends('product_equipment','equipment')
def get_serial_equipment(self):
if self.product_equipment:
raise UserError(str(self.equipment.serial))
return self.equipment.serial
else:
raise UserError(str(self.equipment.serial))
return None
def on_change_with_unit_digits(self, name=None): def on_change_with_unit_digits(self, name=None):
if self.unit: if self.unit:
@ -70,6 +94,7 @@ class SaleLine(metaclass=PoolMeta):
if self.equipment: if self.equipment:
self.product = self.equipment.product.id self.product = self.equipment.product.id
self.address_equipment = self.sale.shipment_address.id self.address_equipment = self.sale.shipment_address.id
self.equipment_serial = self.equipment.serial
self.on_change_product() self.on_change_product()
else: else:
self.address_equipment = None self.address_equipment = None
@ -78,6 +103,7 @@ class SaleLine(metaclass=PoolMeta):
self.quantity = None self.quantity = None
self.unit_price = None self.unit_price = None
self.amount = None self.amount = None
self.equipment_serial = None
self.on_change_product() self.on_change_product()
@fields.depends('product_equipment', methods=['on_change_equipment']) @fields.depends('product_equipment', methods=['on_change_equipment'])
@ -98,45 +124,105 @@ class SaleLine(metaclass=PoolMeta):
self.unit = None self.unit = None
return return
party = None else:
party = None
if self.sale and self.sale.party: if self.sale and self.sale.party:
self.product_equipment = False self.product_equipment = False
party = self.sale.party 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)
# 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: if party and party.customer_tax_rule:
tax_ids = party.customer_tax_rule.apply(tax, pattern) tax_ids = party.customer_tax_rule.apply(None, pattern)
if tax_ids: if tax_ids:
taxes.extend(tax_ids) taxes.extend(tax_ids)
continue self.taxes = taxes
taxes.append(tax.id)
if party and party.customer_tax_rule: category = self.product.sale_uom.category
tax_ids = party.customer_tax_rule.apply(None, pattern) if not self.unit or self.unit.category != category:
if tax_ids: self.unit = self.product.sale_uom
taxes.extend(tax_ids) self.unit_digits = self.product.sale_uom.digits
self.taxes = taxes
category = self.product.sale_uom.category with Transaction().set_context(self._get_context_sale_price()):
if not self.unit or self.unit.category != category: self.unit_price = Product.get_sale_price([self.product],
self.unit = self.product.sale_uom self.quantity or 0)[self.product.id]
self.unit_digits = self.product.sale_uom.digits
with Transaction().set_context(self._get_context_sale_price()): if self.unit_price:
self.unit_price = Product.get_sale_price([self.product], self.unit_price = self.unit_price.quantize(
self.quantity or 0)[self.product.id] Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
if self.unit_price: self.type = 'line'
self.unit_price = self.unit_price.quantize( self.amount = self.on_change_with_amount()
Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
self.type = 'line' if self.product.equipment:
self.amount = self.on_change_with_amount() self.product_equipment = True
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 @classmethod
@ModelView.button @ModelView.button

View File

@ -6,6 +6,16 @@
<field name="inherit" ref="sale.sale_line_view_form"/> <field name="inherit" ref="sale.sale_line_view_form"/>
<field name="name">sale_line_form</field> <field name="name">sale_line_form</field>
</record> </record>
<record model="ir.ui.view" id="sale_line_view_tree">
<field name="model">sale.line</field>
<field name="inherit" ref="sale.sale_line_view_tree"/>
<field name="name">sale_line_tree</field>
</record>
<record model="ir.ui.view" id="sale_line_view_tree_sequence">
<field name="model">sale.line</field>
<field name="inherit" ref="sale.sale_line_view_tree_sequence"/>
<field name="name">sale_line_tree_sequence</field>
</record>
<record model="ir.ui.view" id="create_subscription_view_form"> <record model="ir.ui.view" id="create_subscription_view_form">
<field name="model">sale.create.subscription.start</field> <field name="model">sale.create.subscription.start</field>
<field name="type">form</field> <field name="type">form</field>

View File

@ -23,6 +23,7 @@ xml:
purchase.xml purchase.xml
uom.xml uom.xml
maintenance.xml maintenance.xml
move.xml
subscription.xml subscription.xml
message.xml message.xml

10
view/move_form.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='product']" position="after">
<newline/>
<label name="serial"/>
<field name="serial"/>
</xpath>
</data>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!--This file file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
<data>
<xpath
expr="//field[@name='product']" position="after">
<field name="serial"/>
</xpath>
</data>

View File

@ -59,7 +59,11 @@
<field name="maintenance_history"/> <field name="maintenance_history"/>
</page> </page>
<page string="Origins" id="origins_equipment"> <page string="Origins" id="origins_equipment">
<separator id="purchase_origin" string="Purchase Origin" colspan="4"/>
<field name="purchase_origin"/> <field name="purchase_origin"/>
<newline/>
<separator id="sale_destination" string="Sale Destination" colspan="4"/>
<field name="sale_destination"/>
</page> </page>
</notebook> </notebook>
<group col="2" colspan="2" id="button"> <group col="2" colspan="2" id="button">

View File

@ -10,7 +10,12 @@
expr="/form/notebook/page[@id='general']/label[@name='product']" position="before"> expr="/form/notebook/page[@id='general']/label[@name='product']" position="before">
<label name="product_equipment"/> <label name="product_equipment"/>
<field name="product_equipment"/> <field name="product_equipment"/>
</xpath>
<xpath
expr="/form/notebook/page[@id='general']/field[@name='product']" position="after">
<label name="equipment"/> <label name="equipment"/>
<field name="equipment"/> <field name="equipment"/>
<label name="equipment_serial"/>
<field name="equipment_serial"/>
</xpath> </xpath>
</data> </data>

6
view/sale_line_tree.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<data>
<xpath expr="//field[@name='summary']" position="replace">
<field name="equipment"/>
</xpath>
</data>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<data>
<xpath expr="//field[@name='summary']" position="replace">
<field name="equipment_serial"/>
</xpath>
</data>