mirror of
https://gitlab.com/datalifeit/trytond-stock_party_warehouse
synced 2023-12-14 06:32:52 +01:00
parent
b8fc32ca66
commit
088b0437ec
10 changed files with 197 additions and 16 deletions
|
@ -14,7 +14,11 @@ def register():
|
|||
configuration.ConfigurationPartyWarehouse,
|
||||
party.Party,
|
||||
party.CreateWarehouseStart,
|
||||
party.PartyWarehouse,
|
||||
stock.Location,
|
||||
shipment.ShipmentInReturn,
|
||||
shipment.ShipmentOut,
|
||||
shipment.ShipmentOutReturn,
|
||||
shipment.ShipmentInternal,
|
||||
module='stock_party_warehouse', type_='model')
|
||||
Pool.register(
|
||||
|
|
22
locale/es.po
22
locale/es.po
|
@ -11,6 +11,10 @@ msgctxt "field:party.party,warehouse:"
|
|||
msgid "Party Warehouse"
|
||||
msgstr "Almacén de tercero"
|
||||
|
||||
msgctxt "field:party.party,warehouses:"
|
||||
msgid "Party Warehouses"
|
||||
msgstr "Almacenes de tercero"
|
||||
|
||||
msgctxt "field:party.party,create_warehouse:"
|
||||
msgid "Create Warehouse"
|
||||
msgstr "Crear almacén"
|
||||
|
@ -94,4 +98,20 @@ msgstr "Nuevo almacén"
|
|||
|
||||
msgctxt "view:party.party.create_warehouse.start:"
|
||||
msgid "Existing warehouse"
|
||||
msgstr "Almacén existente"
|
||||
msgstr "Almacén existente"
|
||||
|
||||
msgctxt "model:party.party.warehouse,name:"
|
||||
msgid "Party Warehouse"
|
||||
msgstr "Almacenes de terceros"
|
||||
|
||||
msgctxt "model:ir.ui.menu,name:menu_party_warehouse"
|
||||
msgid "Party Warehouse"
|
||||
msgstr "Almacenes de terceros"
|
||||
|
||||
msgctxt "field:party.party.warehouse,warehouse:"
|
||||
msgid "Warehouse"
|
||||
msgstr "Almacén"
|
||||
|
||||
msgctxt "field:party.party.warehouse,party:"
|
||||
msgid "Party"
|
||||
msgstr "Tercero"
|
||||
|
|
27
model.py
27
model.py
|
@ -6,7 +6,29 @@ from trytond.pyson import Eval
|
|||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class ReturnableMoveMixin(object):
|
||||
class PartyWarehouseMixin(object):
|
||||
|
||||
def _get_party_warehouse_pattern(self):
|
||||
return {}
|
||||
|
||||
@property
|
||||
def party_with_warehouse(self):
|
||||
return self.party
|
||||
|
||||
def get_party_warehouse_used(self, **pattern):
|
||||
party = self.party_with_warehouse
|
||||
if party:
|
||||
wh = party.get_multivalue('warehouse', **pattern)
|
||||
if not wh:
|
||||
# leave only party match pattern value
|
||||
pattern = {key: None if key != 'party' else value
|
||||
for key, value in pattern.items()
|
||||
}
|
||||
wh = party.get_multivalue('warehouse', **pattern)
|
||||
return wh
|
||||
|
||||
|
||||
class ReturnableMoveMixin(PartyWarehouseMixin):
|
||||
|
||||
returnables_moves = fields.Function(
|
||||
fields.One2Many('stock.move', None, 'Returnables moves',
|
||||
|
@ -26,7 +48,8 @@ class ReturnableMoveMixin(object):
|
|||
return moves
|
||||
|
||||
def is_returnable(self, move):
|
||||
return getattr(self, self._party_field).warehouse
|
||||
return self.get_party_warehouse_used(
|
||||
**self._get_party_warehouse_pattern())
|
||||
|
||||
@classmethod
|
||||
def create_returnables_moves(cls, records):
|
||||
|
|
51
party.py
51
party.py
|
@ -1,19 +1,21 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.model import fields, ModelView
|
||||
from trytond.model import fields, ModelView, ModelSQL, ValueMixin
|
||||
from trytond.wizard import Wizard, StateView, Button, StateTransition
|
||||
from trytond.pyson import Not, Bool, Eval
|
||||
from trytond.transaction import Transaction
|
||||
from trytond import backend
|
||||
from sql import Null
|
||||
|
||||
|
||||
class Party(metaclass=PoolMeta):
|
||||
__name__ = 'party.party'
|
||||
|
||||
warehouse = fields.Many2One('stock.location', 'Party Warehouse',
|
||||
domain=[
|
||||
('type', '=', 'warehouse'),
|
||||
])
|
||||
warehouse = fields.MultiValue(fields.Many2One('stock.location',
|
||||
"Party Warehouse", domain=[('type', '=', 'warehouse')]))
|
||||
warehouses = fields.One2Many('party.party.warehouse', 'party',
|
||||
"Party Warehouses")
|
||||
create_warehouse = fields.Function(
|
||||
fields.Boolean('Create Warehouse',
|
||||
states={
|
||||
|
@ -50,6 +52,45 @@ class Party(metaclass=PoolMeta):
|
|||
cls.save(to_save)
|
||||
|
||||
|
||||
class PartyWarehouse(ModelSQL, ModelView, ValueMixin):
|
||||
"Party Warehouse"
|
||||
__name__ = 'party.party.warehouse'
|
||||
|
||||
party = fields.Many2One('party.party', "Party", select=True,
|
||||
required=True, ondelete='CASCADE')
|
||||
warehouse = fields.Many2One('stock.location', "Warehouse",
|
||||
domain=[('type', '=', 'warehouse')], ondelete='RESTRICT')
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
pool = Pool()
|
||||
Party = pool.get('party.party')
|
||||
cursor = Transaction().connection.cursor()
|
||||
table = cls.__table__()
|
||||
party = Party.__table__()
|
||||
exist = backend.TableHandler.table_exist(cls._table)
|
||||
|
||||
super().__register__(module_name)
|
||||
|
||||
if not exist:
|
||||
party_h = Party.__table_handler__(module_name)
|
||||
if party_h.column_exist('warehouse'):
|
||||
cursor.execute(*table.insert([
|
||||
table.create_uid,
|
||||
table.create_date,
|
||||
table.party,
|
||||
table.warehouse,
|
||||
],
|
||||
party.select(
|
||||
party.create_uid,
|
||||
party.create_date,
|
||||
party.id,
|
||||
party.warehouse,
|
||||
where=party.warehouse != Null))
|
||||
)
|
||||
party_h.drop_column('warehouse')
|
||||
|
||||
|
||||
class CreateWarehouseStart(ModelView):
|
||||
"""Create Party Warehouse Start"""
|
||||
__name__ = 'party.party.create_warehouse.start'
|
||||
|
|
31
party.xml
31
party.xml
|
@ -24,5 +24,36 @@
|
|||
<field name="type">form</field>
|
||||
<field name="name">party_create_warehouse_start_form</field>
|
||||
</record>
|
||||
|
||||
<!-- Party Warehouse -->
|
||||
<record model="ir.ui.view" id="party_warehouse_view_form">
|
||||
<field name="model">party.party.warehouse</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">party_warehouse_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="party_warehouse_view_tree">
|
||||
<field name="model">party.party.warehouse</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">party_warehouse_tree</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_party_warehouse">
|
||||
<field name="name">Part Warehouse</field>
|
||||
<field name="res_model">party.party.warehouse</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_party_warehouse_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="party_warehouse_view_tree"/>
|
||||
<field name="act_window" ref="act_party_warehouse"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_party_warehouse_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="party_warehouse_view_form"/>
|
||||
<field name="act_window" ref="act_party_warehouse"/>
|
||||
</record>
|
||||
|
||||
<!-- Menus -->
|
||||
<menuitem action="act_party_warehouse" id="menu_party_warehouse"
|
||||
parent="stock.menu_configuration" sequence="30" name="Party Warehouse"/>
|
||||
|
||||
</data>
|
||||
</tryton>
|
44
shipment.py
44
shipment.py
|
@ -5,13 +5,14 @@ from trytond.model import fields
|
|||
from trytond.pyson import Eval, Not
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.i18n import gettext
|
||||
from trytond.modules.stock_party_warehouse.model import PartyWarehouseMixin
|
||||
|
||||
|
||||
class ShipmentInternal(metaclass=PoolMeta):
|
||||
class ShipmentInternal(PartyWarehouseMixin, metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.internal'
|
||||
|
||||
party = fields.Many2One('party.party', 'Party',
|
||||
domain=[('warehouse', '!=', None)],
|
||||
domain=[('warehouses', '!=', None)],
|
||||
states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| Eval('moves', [0])
|
||||
|
@ -27,22 +28,27 @@ class ShipmentInternal(metaclass=PoolMeta):
|
|||
if (self.party
|
||||
and self.from_location
|
||||
and not self.to_location):
|
||||
if self.from_location.warehouse != self.party.warehouse:
|
||||
self.to_location = self.party.warehouse.storage_location
|
||||
warehouse = self.get_party_warehouse_used(
|
||||
**self._get_party_warehouse_pattern())
|
||||
if self.from_location.warehouse != warehouse:
|
||||
self.to_location = warehouse.storage_location
|
||||
|
||||
@fields.depends('party', 'from_location', 'to_location')
|
||||
def on_change_to_location(self):
|
||||
if (self.party
|
||||
and self.to_location
|
||||
and not self.from_location):
|
||||
if self.to_location.warehouse != self.party.warehouse:
|
||||
self.from_location = self.party.warehouse.storage_location
|
||||
warehouse = self.get_party_warehouse_used(
|
||||
**self._get_party_warehouse_pattern())
|
||||
if self.to_location.warehouse != warehouse:
|
||||
self.from_location = warehouse.storage_location
|
||||
|
||||
@classmethod
|
||||
def wait(cls, shipments, moves=None):
|
||||
for shipment in shipments:
|
||||
if shipment.party:
|
||||
wh = shipment.party.warehouse
|
||||
wh = shipment.get_party_warehouse_used(
|
||||
**shipment._get_party_warehouse_pattern())
|
||||
if (wh != shipment.from_location.warehouse
|
||||
and wh != shipment.to_location.warehouse):
|
||||
raise UserError(gettext('stock_party_warehouse.'
|
||||
|
@ -50,3 +56,27 @@ class ShipmentInternal(metaclass=PoolMeta):
|
|||
shipment=shipment.rec_name,
|
||||
warehouse=wh.rec_name))
|
||||
super().wait(shipments, moves=moves)
|
||||
|
||||
|
||||
class ShipmentInReturn(PartyWarehouseMixin, metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.in.return'
|
||||
|
||||
@property
|
||||
def party_with_warehouse(self):
|
||||
return self.supplier
|
||||
|
||||
|
||||
class ShipmentOut(PartyWarehouseMixin, metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.out'
|
||||
|
||||
@property
|
||||
def party_with_warehouse(self):
|
||||
return self.customer
|
||||
|
||||
|
||||
class ShipmentOutReturn(PartyWarehouseMixin, metaclass=PoolMeta):
|
||||
__name__ = 'stock.shipment.out.return'
|
||||
|
||||
@property
|
||||
def party_with_warehouse(self):
|
||||
return self.customer
|
||||
|
|
|
@ -44,6 +44,12 @@ Add party warehouse parent to stock configuration::
|
|||
>>> conf.party_warehouse_parent = view_loc
|
||||
>>> conf.save()
|
||||
|
||||
Party Warehouse::
|
||||
|
||||
>>> PartyWarehouse = Model.get('party.party.warehouse')
|
||||
>>> party_warehouse = PartyWarehouse.find([])
|
||||
>>> len(party_warehouse)
|
||||
0
|
||||
|
||||
Create parties::
|
||||
|
||||
|
@ -109,6 +115,16 @@ Add parties warehouses::
|
|||
>>> bool(party5.create_warehouse)
|
||||
True
|
||||
|
||||
Check create Party Warehouse::
|
||||
|
||||
>>> PartyWarehouse = Model.get('party.party.warehouse')
|
||||
>>> party_warehouses = PartyWarehouse.find([])
|
||||
>>> len(party_warehouses)
|
||||
5
|
||||
>>> party_warehouse, = PartyWarehouse.find([('party', '=', party)])
|
||||
>>> party_warehouse.warehouse == party.warehouse
|
||||
True
|
||||
|
||||
Add party with create_warehoues check::
|
||||
|
||||
>>> party6 = Party(name='Party 6')
|
||||
|
|
|
@ -4,7 +4,7 @@ depends:
|
|||
ir
|
||||
res
|
||||
production
|
||||
|
||||
|
||||
xml:
|
||||
configuration.xml
|
||||
party.xml
|
||||
|
|
9
view/party_warehouse_form.xml
Normal file
9
view/party_warehouse_form.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<form>
|
||||
<label name="party"/>
|
||||
<field name="party"/>
|
||||
<label name="warehouse"/>
|
||||
<field name="warehouse"/>
|
||||
</form>
|
7
view/party_warehouse_tree.xml
Normal file
7
view/party_warehouse_tree.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<tree editable="1">
|
||||
<field name="party" expand="1"/>
|
||||
<field name="warehouse" expand="1"/>
|
||||
</tree>
|
Loading…
Reference in a new issue