first commit

This commit is contained in:
root
2026-03-14 09:42:12 +00:00
commit 0adbd20c2c
10991 changed files with 1646955 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Местонахождения по подразбиране"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Местонахождения по подразбиране"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Местонахождение на съхранение"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Продукт"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Склад"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Местонахождение на продукт"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Ubicacions predeterminades"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Ubicacions per defecte"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Ubicació d'emmagatzematge"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variant"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Producte"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Magatzem"
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Ubicació de producte"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr ""
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr ""

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Standardlagerorte"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Standardlagerorte"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Lagerort"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variante"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Artikel"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Logistikstandort"
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Artikel Lagerort"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Ubicaciones por defecto"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Ubicaciones por defecto"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Ubicación interna"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variante"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Producto"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Almacén"
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Ubicación de producto"

View File

@@ -0,0 +1,33 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Ubicación de almacenamiento"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Ubicación de almacenamiento"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Bodega"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Ubicación de almacenamiento"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Vaikimisi asukoht"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Vaikimisi asukoht"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Ladustamise asukoht"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Toode"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Ladu"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Toote asukoht"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "مکان های پیشفرض"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "مکان های پیشفرض"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "محل انبار"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "محصول"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "انبار"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "مکان محصول"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr ""
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr ""

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Emplacements par défaut"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Emplacements par défaut"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Emplacement de stockage"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variante"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Produit"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Entrepôt"
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Emplacement du produit en stock"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Alapértelmezett raktár hely"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Alapértelmezett raktár hely"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Raktár helye"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Termék"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Raktár"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Termék raktárhelye"

View File

@@ -0,0 +1,33 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Lokasi Penyimpanan"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Lokasi Penyimpanan"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Produk"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Gudang"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Lokasi Penyimpanan"

View File

@@ -0,0 +1,32 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Luoghi predefiniti"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Luoghi predefiniti"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Luogo immagazzinamento"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variante"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Prodotto"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Magazzino"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Posizione del prodotto"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "ບ່ອນເກັບມ້ຽນເດີມ"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "ບ່ອນເກັບມ້ຽນເດີມ"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "ບ່ອນເກັບມ້ຽນ"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "ຜະລິດຕະພັນ"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "ສາງໃຫຍ່"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "ບ່ອນເກັບມ້ຽນຜະລິດຕະພັນ"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr ""
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr ""

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Standaard locaties"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Standaard locaties"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Opslaglocatie"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Variant"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Product"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Magazijn"
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Voorraad productlocatie"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Domyślne lokalizacje"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Domyślne lokalizacje"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Produkt"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Magazyn"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Lokalizacja produktu"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Localizações padrão"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Localizações padrão"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Localização de armazenamento"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Produto"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Almoxarifado"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Localização do produto"

View File

@@ -0,0 +1,32 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Locații Implicite"
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Locații Implicite"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Locație de Depozitare"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr "Varianta"
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Produs"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Depozit"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Locația Produs"

View File

@@ -0,0 +1,36 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Хранение Местоположение"
#, fuzzy
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Хранение Местоположение"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Товарно материальные ценности (ТМЦ)"
#, fuzzy
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Товарный склад"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Хранение Местоположение"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr "Privzete lokacije"
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Privzete lokacije"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Shramba"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Izdelek"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Skladišče"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Lokacija izdelkov"

View File

@@ -0,0 +1,34 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
#, fuzzy
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr "Ürün Konumu"
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr "Depolama Konumu"
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
#, fuzzy
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr "Ürün"
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr "Depo"
#, fuzzy
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr "Ürün Konumu"

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr ""
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr ""

View File

@@ -0,0 +1,31 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:product.product,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:product.template,locations:"
msgid "Default Locations"
msgstr ""
msgctxt "field:stock.product.location,location:"
msgid "Storage Location"
msgstr ""
msgctxt "field:stock.product.location,product:"
msgid "Variant"
msgstr ""
msgctxt "field:stock.product.location,template:"
msgid "Product"
msgstr ""
msgctxt "field:stock.product.location,warehouse:"
msgid "Warehouse"
msgstr ""
msgctxt "model:stock.product.location,string:"
msgid "Stock Product Location"
msgstr ""

View File

@@ -0,0 +1,102 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import (
MatchMixin, ModelSQL, ModelView, fields, sequence_ordered)
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, If
class ProductLocation(sequence_ordered(), ModelSQL, ModelView, MatchMixin):
"It defines the default storage location by warehouse for a product"
__name__ = 'stock.product.location'
template = fields.Many2One(
'product.template', "Product",
required=True, ondelete='CASCADE',
domain=[
If(Bool(Eval('product')),
('products', '=', Eval('product')),
()),
])
product = fields.Many2One(
'product.product', "Variant", ondelete='CASCADE',
domain=[
If(Bool(Eval('template')),
('template', '=', Eval('template')),
()),
])
warehouse = fields.Many2One('stock.location', 'Warehouse', required=True,
domain=[('type', '=', 'warehouse')], ondelete='CASCADE')
location = fields.Many2One('stock.location', 'Storage Location',
required=True, ondelete='CASCADE',
domain=[
('type', '=', 'storage'),
('parent', 'child_of', If(Bool(Eval('warehouse')),
[Eval('warehouse')], [])),
])
@fields.depends('product', '_parent_product.template')
def on_change_product(self):
if self.product:
self.template = self.product.template
@classmethod
def default_warehouse(cls):
Location = Pool().get('stock.location')
return Location.get_default_warehouse()
class Move(metaclass=PoolMeta):
__name__ = 'stock.move'
def set_product_location(self, field='to_location', **pattern):
"Set the product location on the field"
assert field in {'from_location', 'to_location'}
location = self.get_product_location(**pattern)
if location:
setattr(self, field, location)
def get_product_location(self, **pattern):
"Return the product location for the move"
if (getattr(self, 'shipment', None)
and getattr(self.shipment, 'warehouse', None)):
pattern.setdefault('warehouse', self.shipment.warehouse.id)
elif getattr(self, 'production', None):
pattern.setdefault('warehouse', self.production.warehouse.id)
if self.product:
pattern.setdefault('template', self.product.template.id)
pattern.setdefault('product', self.product.id)
locations = self.product.locations + self.product.template.locations
for product_location in locations:
if product_location.match(pattern):
return product_location.location
@property
def _default_pick_location(self):
location = super()._default_pick_location
if self.product.consumable:
if ((product_location := self.get_product_location())
and product_location.type != 'view'):
location = product_location
return location
class ShipmentIn(metaclass=PoolMeta):
__name__ = 'stock.shipment.in'
def _get_inventory_move(self, incoming_move):
move = super()._get_inventory_move(incoming_move)
if move:
move.set_product_location(warehouse=self.warehouse.id)
return move
class ShipmentOutReturn(metaclass=PoolMeta):
__name__ = 'stock.shipment.out.return'
def _get_inventory_move(self, incoming_move):
move = super()._get_inventory_move(incoming_move)
if move:
move.set_product_location(warehouse=self.warehouse.id)
return move

View File

@@ -0,0 +1,34 @@
<?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. -->
<tryton>
<data>
<record model="ir.ui.view" id="product_location_view_form">
<field name="model">stock.product.location</field>
<field name="type">form</field>
<field name="name">product_location_form</field>
</record>
<record model="ir.ui.view" id="product_location_view_tree">
<field name="model">stock.product.location</field>
<field name="type">tree</field>
<field name="name">product_location_tree</field>
</record>
<record model="ir.model.access" id="access_stock_product_location">
<field name="model">stock.product.location</field>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_stock_product_location_stock_admin">
<field name="model">stock.product.location</field>
<field name="group" ref="stock.group_stock_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,79 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
class Template(metaclass=PoolMeta):
__name__ = 'product.template'
locations = fields.One2Many('stock.product.location', 'template',
"Default Locations",
states={
'invisible': ~Eval('type').in_(['goods', 'assets']),
})
@classmethod
def copy(cls, templates, default=None):
pool = Pool()
ProductLocation = pool.get('stock.product.location')
if default is None:
default = {}
else:
default = default.copy()
copy_locations = 'locations' not in default
default.setdefault('locations', None)
new_templates = super().copy(templates, default)
if copy_locations:
old2new = {}
to_copy = []
for template, new_template in zip(templates, new_templates):
to_copy.extend(l for l in template.locations if not l.product)
old2new[template.id] = new_template.id
if to_copy:
ProductLocation.copy(to_copy, {
'template': lambda d: old2new[d['template']],
})
return new_templates
class Product(metaclass=PoolMeta):
__name__ = 'product.product'
locations = fields.One2Many('stock.product.location', 'product',
"Default Locations",
domain=[
('template', '=', Eval('template', -1)),
],
states={
'invisible': ~Eval('type').in_(['goods', 'assets']),
})
@classmethod
def copy(cls, products, default=None):
pool = Pool()
ProductLocation = pool.get('stock.product.location')
if default is None:
default = {}
else:
default = default.copy()
copy_locations = 'locations' not in default
if 'template' in default:
default.setdefault('locations', None)
new_products = super().copy(products, default)
if 'template' in default and copy_locations:
template2new = {}
product2new = {}
to_copy = []
for product, new_product in zip(products, new_products):
if product.locations:
to_copy.extend(product.locations)
template2new[product.template.id] = new_product.template.id
product2new[product.id] = new_product.id
if to_copy:
ProductLocation.copy(to_copy, {
'product': lambda d: product2new[d['product']],
'template': lambda d: template2new[d['template']],
})
return new_products

View File

@@ -0,0 +1,12 @@
<?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. -->
<tryton>
<data>
<record model="ir.ui.view" id="template_view_form">
<field name="model">product.template</field>
<field name="inherit" ref="product.template_view_form"/>
<field name="name">product_form</field>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,15 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import PoolMeta
class Production(metaclass=PoolMeta):
__name__ = 'production'
@fields.depends('warehouse')
def _move(self, type, product, unit, quantity):
move = super()._move(type, product, unit, quantity)
if move and type == 'output' and self.warehouse:
move.set_product_location(warehouse=self.warehouse.id)
return move

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,61 @@
=============================
Product Copy Locaton Scenario
=============================
Imports::
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.tests.tools import activate_modules, assertEqual
Activate modules::
>>> config = activate_modules('stock_product_location', create_company)
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
Create new location::
>>> Location = Model.get('stock.location')
>>> child_loc = Location()
>>> child_loc.name = 'Child Location'
>>> child_loc.parent = storage_loc
>>> child_loc.code = 'CHI'
>>> child_loc.save()
Create a product with suppliers::
>>> ProductUom = Model.get('product.uom')
>>> ProductTemplate = Model.get('product.template')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> template = ProductTemplate()
>>> template.name = 'Product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.list_price = Decimal('20')
>>> template_location = template.locations.new()
>>> template_location.warehouse = warehouse_loc
>>> template_location.location = child_loc
>>> template.save()
>>> product, = template.products
>>> product_location = product.locations.new()
>>> product_location.warehouse = warehouse_loc
>>> product_location.location = child_loc
>>> assertEqual(product_location.template, template)
>>> product.save()
Location is copied when copying the template::
>>> template_copy, = template.duplicate()
>>> product_copy, = template_copy.products
>>> len(template_copy.locations)
2
>>> len(product_copy.locations)
1

View File

@@ -0,0 +1,122 @@
================================
Stock Product Locations Scenario
================================
Imports::
>>> import datetime as dt
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.modules.currency.tests.tools import get_currency
>>> from trytond.tests.tools import activate_modules, assertEqual
>>> today = dt.date.today()
Activate modules::
>>> config = activate_modules('stock_product_location', create_company)
Get currency::
>>> currency = get_currency()
Create customer::
>>> Party = Model.get('party.party')
>>> customer = Party(name='Customer')
>>> customer.save()
Create supplier::
>>> supplier = Party(name='Suppier')
>>> supplier.save()
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
>>> output_loc, = Location.find([('code', '=', 'OUT')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
>>> input_loc, = Location.find([('code', '=', 'IN')])
Create new location::
>>> Location = Model.get('stock.location')
>>> child_loc = Location()
>>> child_loc.name = 'Child Location'
>>> child_loc.parent = storage_loc
>>> child_loc.code = 'CHI'
>>> child_loc.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> ProductTemplate = Model.get('product.template')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> template = ProductTemplate()
>>> template.name = 'Product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.list_price = Decimal('20')
>>> template.save()
>>> product, = template.products
>>> product_location = product.locations.new()
>>> product_location.warehouse = warehouse_loc
>>> product_location.location = child_loc
>>> product.save()
Create Shipment in::
>>> Shipmentin = Model.get('stock.shipment.in')
>>> shipment_in = Shipmentin()
>>> shipment_in.planned_date = today
>>> shipment_in.supplier = supplier
>>> shipment_in.warehouse = warehouse_loc
Add one shipment line of product::
>>> move = shipment_in.incoming_moves.new()
>>> move.product = product
>>> move.unit = unit
>>> move.quantity = 1
>>> move.from_location = supplier_loc
>>> move.to_location = input_loc
>>> move.unit_price = Decimal('1')
>>> move.currency = currency
>>> shipment_in.save()
Test that to_location is child location on reception::
>>> shipment_in.click('receive')
>>> move, = shipment_in.inventory_moves
>>> assertEqual(move.to_location, child_loc)
Create return shipment out::
>>> Shipment_out_Return = Model.get('stock.shipment.out.return')
>>> shipment_out_return = Shipment_out_Return()
>>> shipment_out_return.customer = customer
>>> shipment_out_return.save()
Add one shipment return line::
>>> move = shipment_out_return.incoming_moves.new()
>>> move.product = product
>>> move.unit = unit
>>> move.quantity = 1
>>> move.from_location = customer_loc
>>> move.to_location = input_loc
>>> move.unit_price = Decimal('1')
>>> move.currency = currency
>>> shipment_out_return.save()
Test that to_location is child location on reception::
>>> shipment_out_return.click('receive')
>>> move, = shipment_out_return.inventory_moves
>>> assertEqual(move.to_location, child_loc)

View File

@@ -0,0 +1,73 @@
==========================================
Stock Product Location Consumable Scenario
==========================================
Imports::
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.tests.tools import activate_modules, assertEqual
Activate modules::
>>> config = activate_modules('stock_product_location', create_company)
>>> Location = Model.get('stock.location')
>>> Party = Model.get('party.party')
>>> ProductTemplate = Model.get('product.template')
>>> ShipmentOut = Model.get('stock.shipment.out')
>>> UoM = Model.get('product.uom')
Create customer::
>>> customer = Party(name="Customer")
>>> customer.save()
Create consumable location::
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> consumable_loc = Location(name="Consumable")
>>> consumable_loc.parent = warehouse_loc
>>> consumable_loc.save()
Create consumable product::
>>> unit, = UoM.find([('name', '=', "Unit")])
>>> template = ProductTemplate(name="Consumable")
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.consumable = True
>>> product_location = template.locations.new()
>>> product_location.warehouse = warehouse_loc
>>> product_location.location = consumable_loc
>>> template.save()
>>> product, = template.products
Ship consumable product to customer::
>>> shipment = ShipmentOut(customer=customer)
>>> move = shipment.outgoing_moves.new()
>>> move.product = product
>>> move.quantity = 1
>>> move.from_location = shipment.warehouse_output
>>> move.to_location = shipment.customer_location
>>> move.unit_price = Decimal(0)
>>> move.currency = shipment.company.currency
>>> shipment.click('wait')
>>> shipment.state
'waiting'
Assign the shipment::
>>> shipment_assign = shipment.click('assign_wizard')
>>> shipment.state
'assigned'
Check assigned from consumable location::
>>> move, = shipment.inventory_moves
>>> assertEqual(move.from_location, consumable_loc)

View File

@@ -0,0 +1,141 @@
===========================================
Stock Product Locations Production Scenario
===========================================
Imports::
>>> import datetime as dt
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.tests.tools import activate_modules, assertEqual
>>> today = dt.date.today()
Activate modules::
>>> _ = activate_modules(['stock_product_location', 'production'], create_company)
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
>>> production_loc, = Location.find([('code', '=', 'PROD')])
Create new location::
>>> Location = Model.get('stock.location')
>>> child_loc = Location()
>>> child_loc.name = 'Child Location'
>>> child_loc.parent = storage_loc
>>> child_loc.code = 'CHI'
>>> child_loc.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.producible = True
>>> template.list_price = Decimal(30)
>>> template.save()
>>> product, = template.products
>>> product_location = product.locations.new()
>>> product_location.warehouse = warehouse_loc
>>> product_location.location = child_loc
>>> product.save()
Create Components::
>>> template1 = ProductTemplate()
>>> template1.name = 'component 1'
>>> template1.default_uom = unit
>>> template1.type = 'goods'
>>> template1.list_price = Decimal(5)
>>> template1.save()
>>> component1, = template1.products
>>> meter, = ProductUom.find([('name', '=', 'Meter')])
>>> centimeter, = ProductUom.find([('name', '=', 'Centimeter')])
>>> template2 = ProductTemplate()
>>> template2.name = 'component 2'
>>> template2.default_uom = meter
>>> template2.type = 'goods'
>>> template2.list_price = Decimal(7)
>>> template2.save()
>>> component2, = template2.products
Create Bill of Material::
>>> BOM = Model.get('production.bom')
>>> BOMInput = Model.get('production.bom.input')
>>> BOMOutput = Model.get('production.bom.output')
>>> bom = BOM(name='product')
>>> input1 = BOMInput()
>>> bom.inputs.append(input1)
>>> input1.product = component1
>>> input1.quantity = 5
>>> input2 = BOMInput()
>>> bom.inputs.append(input2)
>>> input2.product = component2
>>> input2.quantity = 150
>>> input2.unit = centimeter
>>> output = BOMOutput()
>>> bom.outputs.append(output)
>>> output.product = product
>>> output.quantity = 1
>>> bom.save()
>>> ProductBom = Model.get('product.product-production.bom')
>>> product.boms.append(ProductBom(bom=bom))
>>> product.save()
Create an Inventory::
>>> Inventory = Model.get('stock.inventory')
>>> InventoryLine = Model.get('stock.inventory.line')
>>> inventory = Inventory()
>>> inventory.location = storage_loc
>>> inventory_line1 = InventoryLine()
>>> inventory.lines.append(inventory_line1)
>>> inventory_line1.product = component1
>>> inventory_line1.quantity = 20
>>> inventory_line2 = InventoryLine()
>>> inventory.lines.append(inventory_line2)
>>> inventory_line2.product = component2
>>> inventory_line2.quantity = 6
>>> inventory.click('confirm')
>>> inventory.state
'done'
Make a production::
>>> Production = Model.get('production')
>>> production = Production()
>>> production.planned_date = today
>>> production.product = product
>>> production.bom = bom
>>> production.quantity = 2
Test storage location of the warehouse::
>> assertEqual(warehouse_loc.storage_location, storage_loc)
Test locations of the production inputs::
>>> for input_ in production.inputs:
... assertEqual(input_.from_location, storage_loc)
... assertEqual(input_.to_location, production_loc)
Test location of the production output::
>>> output, = production.outputs
>>> assertEqual(output.from_location, production_loc)
>>> assertEqual(output.to_location, child_loc)

View File

@@ -0,0 +1,121 @@
=========================================
Stock Product Locations Template Scenario
=========================================
Imports::
>>> import datetime as dt
>>> from decimal import Decimal
>>> from proteus import Model
>>> from trytond.modules.company.tests.tools import create_company
>>> from trytond.modules.currency.tests.tools import get_currency
>>> from trytond.tests.tools import activate_modules, assertEqual
>>> today = dt.date.today()
Activate modules::
>>> config = activate_modules('stock_product_location', create_company)
Get currency::
>>> currency = get_currency()
Create customer::
>>> Party = Model.get('party.party')
>>> customer = Party(name='Customer')
>>> customer.save()
Create supplier::
>>> supplier = Party(name='Suppier')
>>> supplier.save()
Get stock locations::
>>> Location = Model.get('stock.location')
>>> warehouse_loc, = Location.find([('code', '=', 'WH')])
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
>>> output_loc, = Location.find([('code', '=', 'OUT')])
>>> storage_loc, = Location.find([('code', '=', 'STO')])
>>> input_loc, = Location.find([('code', '=', 'IN')])
Create new location::
>>> Location = Model.get('stock.location')
>>> child_loc = Location()
>>> child_loc.name = 'Child Location'
>>> child_loc.parent = storage_loc
>>> child_loc.code = 'CHI'
>>> child_loc.save()
Create product::
>>> ProductUom = Model.get('product.uom')
>>> ProductTemplate = Model.get('product.template')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> template = ProductTemplate()
>>> template.name = 'Product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.list_price = Decimal('20')
>>> template_location = template.locations.new()
>>> template_location.warehouse = warehouse_loc
>>> template_location.location = child_loc
>>> template.save()
>>> product, = template.products
Create Shipment in::
>>> Shipmentin = Model.get('stock.shipment.in')
>>> shipment_in = Shipmentin()
>>> shipment_in.planned_date = today
>>> shipment_in.supplier = supplier
>>> shipment_in.warehouse = warehouse_loc
Add one shipment line of product::
>>> move = shipment_in.incoming_moves.new()
>>> move.product = product
>>> move.unit = unit
>>> move.quantity = 1
>>> move.from_location = supplier_loc
>>> move.to_location = input_loc
>>> move.unit_price = Decimal('1')
>>> move.currency = currency
>>> shipment_in.save()
Test that to_location is child location on reception::
>>> shipment_in.click('receive')
>>> move, = shipment_in.inventory_moves
>>> assertEqual(move.to_location, child_loc)
Create return shipment out::
>>> Shipment_out_Return = Model.get('stock.shipment.out.return')
>>> shipment_out_return = Shipment_out_Return()
>>> shipment_out_return.customer = customer
>>> shipment_out_return.save()
Add one shipment return line::
>>> move = shipment_out_return.incoming_moves.new()
>>> move.product = product
>>> move.unit = unit
>>> move.quantity = 1
>>> move.from_location = customer_loc
>>> move.to_location = input_loc
>>> move.unit_price = Decimal('1')
>>> move.currency = currency
>>> shipment_out_return.save()
Test that to_location is child location on reception::
>>> shipment_out_return.click('receive')
>>> move, = shipment_out_return.inventory_moves
>>> assertEqual(move.to_location, child_loc)

View File

@@ -0,0 +1,13 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.tests.test_tryton import ModuleTestCase
class StockProductLocationTestCase(ModuleTestCase):
'Test StockProductLocation module'
module = 'stock_product_location'
extras = ['production']
del ModuleTestCase

View File

@@ -0,0 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.tests.test_tryton import load_doc_tests
def load_tests(*args, **kwargs):
return load_doc_tests(__name__, __file__, *args, **kwargs)

View File

@@ -0,0 +1,24 @@
[tryton]
version=7.8.0
depends:
ir
product
stock
extras_depend:
production
xml:
location.xml
product.xml
[register]
model:
product.Template
product.Product
location.ProductLocation
location.Move
location.ShipmentIn
location.ShipmentOutReturn
[register production]
model:
production.Production

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/notebook" position="inside">
<page name="locations">
<field name="locations" colspan="6"/>
</page>
</xpath>
</data>

View File

@@ -0,0 +1,16 @@
<?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. -->
<form cursor="product">
<label name="template"/>
<field name="template"/>
<newline/>
<label name="sequence"/>
<field name="sequence"/>
<label name="product"/>
<field name="product"/>
<label name="warehouse"/>
<field name="warehouse"/>
<label name="location"/>
<field name="location"/>
</form>

View File

@@ -0,0 +1,9 @@
<?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. -->
<tree>
<field name="template" expand="2"/>
<field name="product" expand="2"/>
<field name="warehouse" expand="1"/>
<field name="location" expand="1"/>
</tree>