shipment equipments
This commit is contained in:
parent
c4151da4f2
commit
9e73d4ec09
@ -1,6 +1,6 @@
|
||||
from trytond.pool import Pool
|
||||
from . import (address, diary, party, product, purchase, sale,
|
||||
equipment, configuration_equipment, maintenance, subscription, exceptions)
|
||||
equipment, configuration_equipment, maintenance, move, subscription, exceptions)
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
@ -12,6 +12,7 @@ def register():
|
||||
purchase.Purchase,
|
||||
purchase.Line,
|
||||
sale.Sale,
|
||||
sale.SaleLine,
|
||||
sale.CreateSubscriptionStart,
|
||||
equipment.OpticalEquipment,
|
||||
equipment.EquipmentMaintenance,
|
||||
@ -19,11 +20,11 @@ def register():
|
||||
maintenance.Maintenance,
|
||||
maintenance.MaintenanceActivity,
|
||||
maintenance.MaintenanceLine,
|
||||
move.Move,
|
||||
move.ShipmentOut,
|
||||
subscription.Subscription,
|
||||
subscription.SubscriptionEquipment,
|
||||
#subscription.CreateContractInvoiceStart,
|
||||
module='optical_equipment', type_='model')
|
||||
Pool.register(
|
||||
sale.CreateSubscription,
|
||||
#subscription.CreateContractInvoice,
|
||||
module='optical_equipment', type_='wizard')
|
||||
|
24
equipment.py
24
equipment.py
@ -104,6 +104,10 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
|
||||
purchase_origin = fields.Reference("Purchase Origin", selection='get_origin',select=True,
|
||||
states={'readonly': True})
|
||||
|
||||
sale_destination = fields.Reference("Sale Destination", selection='get_destination',select=True,
|
||||
states={'readonly': True})
|
||||
|
||||
|
||||
del _states_serial, _states, _depends
|
||||
|
||||
@classmethod
|
||||
@ -129,6 +133,24 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
|
||||
|
||||
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
|
||||
def __setup__(cls):
|
||||
@ -142,7 +164,7 @@ class OpticalEquipment(DeactivableMixin, Workflow, ModelSQL, ModelView):
|
||||
# 'draft': {
|
||||
# 'invisible': Eval('state') == 'draft'},
|
||||
'registred': {
|
||||
'invisible': Eval('state').in_(['registred', 'contrated'])}}
|
||||
'invisible': Eval('state').in_(['registred', 'uncontrated', 'contrated'])}}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
53
move.py
Normal file
53
move.py
Normal 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
14
move.xml
Normal 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
148
sale.py
@ -1,7 +1,7 @@
|
||||
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
|
||||
from trytond.pyson import Eval, Bool, If, Get
|
||||
from decimal import Decimal
|
||||
from trytond.modules.product import price_digits
|
||||
from trytond.transaction import Transaction
|
||||
@ -18,6 +18,7 @@ class Sale(metaclass=PoolMeta):
|
||||
'Sale'
|
||||
__name__ = 'sale.sale'
|
||||
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('confirmed')
|
||||
@ -39,13 +40,24 @@ class Sale(metaclass=PoolMeta):
|
||||
equipment.propietary=sale.party.id
|
||||
equipment.propietary_address=sale.shipment_address.id
|
||||
equipment.state="uncontrated"
|
||||
equipment.sale_destination = line
|
||||
equipment.maintenance_frequency = "6" if sale.party.client_type == "ips" else "12"
|
||||
equipment.save()
|
||||
|
||||
with Transaction().set_context(
|
||||
queue_name='sale',
|
||||
queue_scheduled_at=config.sale_process_after):
|
||||
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):
|
||||
'SaleLine'
|
||||
@ -56,9 +68,21 @@ class SaleLine(metaclass=PoolMeta):
|
||||
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')
|
||||
|
||||
@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):
|
||||
if self.unit:
|
||||
@ -70,6 +94,7 @@ class SaleLine(metaclass=PoolMeta):
|
||||
if self.equipment:
|
||||
self.product = self.equipment.product.id
|
||||
self.address_equipment = self.sale.shipment_address.id
|
||||
self.equipment_serial = self.equipment.serial
|
||||
self.on_change_product()
|
||||
else:
|
||||
self.address_equipment = None
|
||||
@ -78,6 +103,7 @@ class SaleLine(metaclass=PoolMeta):
|
||||
self.quantity = None
|
||||
self.unit_price = None
|
||||
self.amount = None
|
||||
self.equipment_serial = None
|
||||
self.on_change_product()
|
||||
|
||||
@fields.depends('product_equipment', methods=['on_change_equipment'])
|
||||
@ -98,45 +124,105 @@ class SaleLine(metaclass=PoolMeta):
|
||||
self.unit = None
|
||||
return
|
||||
|
||||
party = None
|
||||
else:
|
||||
party = None
|
||||
|
||||
if self.sale and self.sale.party:
|
||||
self.product_equipment = False
|
||||
party = self.sale.party
|
||||
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)
|
||||
|
||||
# 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)
|
||||
tax_ids = party.customer_tax_rule.apply(None, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
continue
|
||||
taxes.append(tax.id)
|
||||
self.taxes = taxes
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
|
||||
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])
|
||||
|
||||
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()
|
||||
|
||||
self.type = 'line'
|
||||
self.amount = self.on_change_with_amount()
|
||||
self.product_equipment = True
|
||||
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
|
||||
|
10
sale.xml
10
sale.xml
@ -6,6 +6,16 @@
|
||||
<field name="inherit" ref="sale.sale_line_view_form"/>
|
||||
<field name="name">sale_line_form</field>
|
||||
</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">
|
||||
<field name="model">sale.create.subscription.start</field>
|
||||
<field name="type">form</field>
|
||||
|
@ -23,6 +23,7 @@ xml:
|
||||
purchase.xml
|
||||
uom.xml
|
||||
maintenance.xml
|
||||
move.xml
|
||||
subscription.xml
|
||||
message.xml
|
||||
|
10
view/move_form.xml
Normal file
10
view/move_form.xml
Normal 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>
|
8
view/move_list_shipment.xml
Normal file
8
view/move_list_shipment.xml
Normal 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>
|
@ -59,7 +59,11 @@
|
||||
<field name="maintenance_history"/>
|
||||
</page>
|
||||
<page string="Origins" id="origins_equipment">
|
||||
<separator id="purchase_origin" string="Purchase Origin" colspan="4"/>
|
||||
<field name="purchase_origin"/>
|
||||
<newline/>
|
||||
<separator id="sale_destination" string="Sale Destination" colspan="4"/>
|
||||
<field name="sale_destination"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="2" colspan="2" id="button">
|
||||
|
@ -10,7 +10,12 @@
|
||||
expr="/form/notebook/page[@id='general']/label[@name='product']" position="before">
|
||||
<label name="product_equipment"/>
|
||||
<field name="product_equipment"/>
|
||||
</xpath>
|
||||
<xpath
|
||||
expr="/form/notebook/page[@id='general']/field[@name='product']" position="after">
|
||||
<label name="equipment"/>
|
||||
<field name="equipment"/>
|
||||
<label name="equipment_serial"/>
|
||||
<field name="equipment_serial"/>
|
||||
</xpath>
|
||||
</data>
|
||||
|
6
view/sale_line_tree.xml
Normal file
6
view/sale_line_tree.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath expr="//field[@name='summary']" position="replace">
|
||||
<field name="equipment"/>
|
||||
</xpath>
|
||||
</data>
|
6
view/sale_line_tree_sequence.xml
Normal file
6
view/sale_line_tree_sequence.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<data>
|
||||
<xpath expr="//field[@name='summary']" position="replace">
|
||||
<field name="equipment_serial"/>
|
||||
</xpath>
|
||||
</data>
|
Loading…
Reference in New Issue
Block a user