Active Record
This commit is contained in:
+14
@@ -1,6 +1,20 @@
|
||||
#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.pool import Pool
|
||||
from stock import *
|
||||
from production import *
|
||||
from product import *
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
OrderPoint,
|
||||
Configuration,
|
||||
Production,
|
||||
CreateProductionRequestStart,
|
||||
Product,
|
||||
module='stock_supply_production', type_='model')
|
||||
Pool.register(
|
||||
CreateProductionRequest,
|
||||
module='stock_supply_production', type_='wizard')
|
||||
|
||||
+9
-9
@@ -1,17 +1,17 @@
|
||||
#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 Model
|
||||
from trytond.pool import Pool
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
|
||||
__all__ = ['Product']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
||||
class Product(Model):
|
||||
_name = 'product.product'
|
||||
class Product:
|
||||
__name__ = 'product.product'
|
||||
|
||||
def get_supply_period(self, product):
|
||||
def get_supply_period(self):
|
||||
'Return the supply period for the product'
|
||||
pool = Pool()
|
||||
configuration_obj = pool.get('production.configuration')
|
||||
return int(configuration_obj.browse(1).supply_period or 0)
|
||||
|
||||
Product()
|
||||
Configuration = pool.get('production.configuration')
|
||||
return int(Configuration(1).supply_period or 0)
|
||||
|
||||
+61
-65
@@ -3,28 +3,31 @@
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from trytond.model import Model, ModelView, fields
|
||||
from trytond.pool import Pool
|
||||
from trytond.model import ModelView, fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.wizard import Wizard, StateView, StateAction, Button
|
||||
|
||||
__all__ = ['Configuration', 'Production',
|
||||
'CreateProductionRequestStart', 'CreateProductionRequest']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
class Configuration(Model):
|
||||
_name = 'production.configuration'
|
||||
|
||||
class Configuration:
|
||||
__name__ = 'production.configuration'
|
||||
supply_period = fields.Property(fields.Numeric('Supply Period',
|
||||
digits=(16, 0), help='In number of days', required=True))
|
||||
|
||||
def default_supply_period(self):
|
||||
@staticmethod
|
||||
def default_supply_period():
|
||||
return Decimal(0)
|
||||
|
||||
Configuration()
|
||||
|
||||
class Production:
|
||||
__name__ = 'production'
|
||||
|
||||
class Production(Model):
|
||||
_name = 'production'
|
||||
|
||||
def generate_requests(self, clean=True):
|
||||
@classmethod
|
||||
def generate_requests(cls, clean=True):
|
||||
"""
|
||||
For each product compute the production request that must be created
|
||||
today to meet product outputs.
|
||||
@@ -32,97 +35,98 @@ class Production(Model):
|
||||
If clean is set, it will remove all previous requests.
|
||||
"""
|
||||
pool = Pool()
|
||||
order_point_obj = pool.get('stock.order_point')
|
||||
product_obj = pool.get('product.product')
|
||||
location_obj = pool.get('stock.location')
|
||||
date_obj = pool.get('ir.date')
|
||||
user_obj = pool.get('res.user')
|
||||
company = user_obj.browse(Transaction().user).company
|
||||
OrderPoint = pool.get('stock.order_point')
|
||||
Product = pool.get('product.product')
|
||||
Location = pool.get('stock.location')
|
||||
Date = pool.get('ir.date')
|
||||
User = pool.get('res.user')
|
||||
company = User(Transaction().user).company
|
||||
|
||||
if clean:
|
||||
req_ids = self.search([
|
||||
reqs = cls.search([
|
||||
('state', '=', 'request'),
|
||||
])
|
||||
self.delete(req_ids)
|
||||
cls.delete(reqs)
|
||||
|
||||
# fetch warehouse
|
||||
warehouse_ids = location_obj.search([
|
||||
warehouses = Location.search([
|
||||
('type', '=', 'warehouse'),
|
||||
])
|
||||
warehouses = location_obj.browse(warehouse_ids)
|
||||
warehouse_ids = [w.id for w in warehouses]
|
||||
# fetch order points
|
||||
order_point_ids = order_point_obj.search([
|
||||
order_points = OrderPoint.search([
|
||||
('type', '=', 'production'),
|
||||
])
|
||||
# index them by product
|
||||
product2ops = {}
|
||||
for order_point in order_point_obj.browse(order_point_ids):
|
||||
for order_point in order_points:
|
||||
product2ops[
|
||||
(order_point.warehouse_location.id, order_point.product.id)
|
||||
] = order_point
|
||||
|
||||
# fetch goods
|
||||
product_ids = product_obj.search([
|
||||
products = Product.search([
|
||||
('type', '=', 'goods'),
|
||||
('consumable', '=', False),
|
||||
('purchasable', '=', False),
|
||||
])
|
||||
products = product_obj.browse(product_ids)
|
||||
# order product by supply period
|
||||
products_period = sorted([(product_obj.get_supply_period(p), p)
|
||||
for p in products])
|
||||
products_period = sorted([(p.get_supply_period(), p)
|
||||
for p in products])
|
||||
|
||||
# compute requests
|
||||
cursor = Transaction().cursor
|
||||
today = date_obj.today()
|
||||
today = Date.today()
|
||||
requests = []
|
||||
for i in range(0, len(products), cursor.IN_MAX):
|
||||
product_ids = [p.id for p in products[i:i + cursor.IN_MAX]]
|
||||
with Transaction().set_context(forecast=True,
|
||||
stock_date_end=today):
|
||||
pbl = product_obj.products_by_location(warehouse_ids,
|
||||
pbl = Product.products_by_location(warehouse_ids,
|
||||
product_ids, with_childs=True, skip_zero=False)
|
||||
for warehouse in warehouses:
|
||||
quantities = dict((x, pbl.pop((warehouse.id, x)))
|
||||
for x in product_ids)
|
||||
shortages = self.get_shortage(warehouse.id, product_ids, today,
|
||||
shortages = cls.get_shortage(warehouse.id, product_ids, today,
|
||||
quantities, products_period, product2ops)
|
||||
|
||||
for product in products[i:i + cursor.IN_MAX]:
|
||||
for date, quantity in shortages[product.id]:
|
||||
req_values = self.compute_request(product, warehouse,
|
||||
req = cls.compute_request(product, warehouse,
|
||||
quantity, date, company)
|
||||
req_id = self.create(req_values)
|
||||
self.set_moves(self.browse(req_id))
|
||||
requests.append(req_id)
|
||||
req.save()
|
||||
req.set_moves()
|
||||
requests.append(req)
|
||||
if requests:
|
||||
self.generate_requests(clean=False)
|
||||
cls.generate_requests(clean=False)
|
||||
return requests
|
||||
|
||||
def compute_request(self, product, warehouse, quantity, date, company):
|
||||
@classmethod
|
||||
def compute_request(cls, product, warehouse, quantity, date, company):
|
||||
"""
|
||||
Return the value of the production request.
|
||||
"""
|
||||
pool = Pool()
|
||||
date_obj = pool.get('ir.date')
|
||||
today = date_obj.today()
|
||||
Date = pool.get('ir.date')
|
||||
today = Date.today()
|
||||
if date <= today:
|
||||
date = today
|
||||
else:
|
||||
date -= datetime.timedelta(1)
|
||||
return {
|
||||
'planned_date': date,
|
||||
'company': company.id,
|
||||
'warehouse': warehouse.id,
|
||||
'location': warehouse.production_location.id,
|
||||
'product': product.id,
|
||||
'bom': product.boms[0].bom.id if product.boms else None,
|
||||
'uom': product.default_uom.id,
|
||||
'quantity': quantity,
|
||||
'state': 'request',
|
||||
}
|
||||
return cls(
|
||||
planned_date=date,
|
||||
company=company,
|
||||
warehouse=warehouse,
|
||||
location=warehouse.production_location,
|
||||
product=product,
|
||||
bom=product.boms[0].bom if product.boms else None,
|
||||
uom=product.default_uom,
|
||||
quantity=quantity,
|
||||
state='request',
|
||||
)
|
||||
|
||||
def get_shortage(self, location_id, product_ids, date, quantities,
|
||||
@classmethod
|
||||
def get_shortage(cls, location_id, product_ids, date, quantities,
|
||||
products_period, order_points):
|
||||
"""
|
||||
Return for each product a list of dates where the stock quantity is
|
||||
@@ -137,7 +141,7 @@ class Production(Model):
|
||||
order_points is a dictionary that links products to order points.
|
||||
"""
|
||||
pool = Pool()
|
||||
product_obj = pool.get('product.product')
|
||||
Product = pool.get('product.product')
|
||||
|
||||
shortages = {}
|
||||
|
||||
@@ -170,7 +174,7 @@ class Production(Model):
|
||||
# Update current quantities
|
||||
with Transaction().set_context(stock_date_start=current_date,
|
||||
stock_date_end=current_date):
|
||||
pbl = product_obj.products_by_location([location_id],
|
||||
pbl = Product.products_by_location([location_id],
|
||||
product_ids, with_childs=True, skip_zero=False)
|
||||
for key, qty in pbl.iteritems():
|
||||
_, product_id = key
|
||||
@@ -185,21 +189,15 @@ class Production(Model):
|
||||
|
||||
return shortages
|
||||
|
||||
Production()
|
||||
|
||||
|
||||
class CreateProductionRequestStart(ModelView):
|
||||
'Create Production Request'
|
||||
_name = 'production.create_request.start'
|
||||
_description = __doc__
|
||||
|
||||
CreateProductionRequestStart()
|
||||
__name__ = 'production.create_request.start'
|
||||
|
||||
|
||||
class CreateProductionRequest(Wizard):
|
||||
'Create Production Request'
|
||||
_name = 'production.create_request'
|
||||
|
||||
__name__ = 'production.create_request'
|
||||
start = StateView('production.create_request.start',
|
||||
'stock_supply_production.production_create_request_start_view_form', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
@@ -207,13 +205,11 @@ class CreateProductionRequest(Wizard):
|
||||
])
|
||||
create_ = StateAction('production.act_production_request')
|
||||
|
||||
def do_create_(self, session, action):
|
||||
def do_create_(self, action):
|
||||
pool = Pool()
|
||||
production_obj = pool.get('production')
|
||||
production_obj.generate_requests()
|
||||
Production = pool.get('production')
|
||||
Production.generate_requests()
|
||||
return action, {}
|
||||
|
||||
def transition_create_(self, session):
|
||||
def transition_create_(self):
|
||||
return 'end'
|
||||
|
||||
CreateProductionRequest()
|
||||
|
||||
@@ -1,46 +1,39 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
import copy
|
||||
|
||||
from trytond.model import Model
|
||||
from trytond.pyson import Eval
|
||||
from trytond.pool import PoolMeta
|
||||
|
||||
__all__ = ['OrderPoint']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
||||
class OrderPoint(Model):
|
||||
_name = 'stock.order_point'
|
||||
class OrderPoint:
|
||||
__name__ = 'stock.order_point'
|
||||
|
||||
def __init__(self):
|
||||
super(OrderPoint, self).__init__()
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(OrderPoint, cls).__setup__()
|
||||
|
||||
self.warehouse_location = copy.copy(self.warehouse_location)
|
||||
states = copy.copy(self.warehouse_location.states)
|
||||
states['invisible'] = (states['invisible']
|
||||
& (Eval('type') != 'production'))
|
||||
states['required'] = (states['required']
|
||||
| (Eval('type') == 'production'))
|
||||
self.warehouse_location.states = states
|
||||
cls.warehouse_location.states['invisible'] &= (
|
||||
Eval('type') != 'production')
|
||||
cls.warehouse_location.states['required'] |= (
|
||||
Eval('type') == 'production')
|
||||
|
||||
option = ('production', 'Production')
|
||||
if option not in self.type.selection:
|
||||
self.type = copy.copy(self.type)
|
||||
self.type.selection = copy.copy(self.type.selection)
|
||||
self.type.selection.append(option)
|
||||
if option not in cls.type.selection:
|
||||
cls.type.selection.append(option)
|
||||
|
||||
self._reset_columns()
|
||||
|
||||
def _type2field(self, type=None):
|
||||
@classmethod
|
||||
def _type2field(cls, type=None):
|
||||
if type == 'production':
|
||||
return 'warehouse_location'
|
||||
result = super(OrderPoint, self)._type2field(type=type)
|
||||
result = super(OrderPoint, cls)._type2field(type=type)
|
||||
if type == None:
|
||||
result['production'] = 'warehouse_location'
|
||||
return result
|
||||
|
||||
def get_location(self, ids, name):
|
||||
locations = super(OrderPoint, self).get_location(ids, name)
|
||||
for op in self.browse(ids):
|
||||
if op.type == 'production':
|
||||
locations[op.id] = op.warehouse_location.id
|
||||
return locations
|
||||
|
||||
OrderPoint()
|
||||
def get_location(self, name):
|
||||
location = super(OrderPoint, self).get_location(name)
|
||||
if self.type == 'production':
|
||||
return self.warehouse_location.id
|
||||
return location
|
||||
|
||||
Reference in New Issue
Block a user