mirror of
https://bitbucket.org/presik/trytonpsk-stock_co.git
synced 2023-12-14 05:43:05 +01:00
793 lines
30 KiB
Python
793 lines
30 KiB
Python
# 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 datetime import date, datetime, timedelta
|
|
from decimal import Decimal
|
|
from trytond.model import fields, ModelView
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval, Not, Bool
|
|
from trytond.wizard import Wizard, StateView, StateReport, Button
|
|
from trytond.report import Report
|
|
from trytond.transaction import Transaction
|
|
|
|
STATES = {'invisible': (Eval('type') != 'goods')}
|
|
|
|
|
|
STATES_MOVE = {
|
|
'readonly': Eval('state').in_(['cancel', 'assigned', 'done']),
|
|
}
|
|
|
|
|
|
class Lot(metaclass=PoolMeta):
|
|
__name__ = 'stock.lot'
|
|
active = fields.Boolean('Active')
|
|
|
|
@staticmethod
|
|
def default_active():
|
|
return True
|
|
|
|
|
|
class Move(metaclass=PoolMeta):
|
|
__name__ = 'stock.move'
|
|
description = fields.Char('Description', select=True, states=STATES_MOVE)
|
|
current_stock = fields.Function(fields.Float('Current Stock',
|
|
depends=['product']), 'on_change_with_current_stock')
|
|
reference = fields.Function(fields.Char('Reference',
|
|
depends=['product'], help='reference of product'), 'get_reference')
|
|
|
|
@fields.depends('current_stock')
|
|
def on_change_product(self, name=None):
|
|
super(Move, self).on_change_product()
|
|
self.current_stock = self.on_change_with_current_stock()
|
|
|
|
@fields.depends('product')
|
|
def get_reference(self, name=None):
|
|
reference = None
|
|
if self.product and hasattr(self.product, 'reference') and self.product.reference:
|
|
reference = self.product.reference
|
|
return reference
|
|
|
|
@fields.depends('product', 'from_location', 'to_location')
|
|
def on_change_with_current_stock(self, name=None):
|
|
res = 0
|
|
location = None
|
|
if self.from_location and self.from_location.type == 'storage':
|
|
location = self.from_location.parent.storage_location
|
|
elif self.to_location and self.to_location.type == 'storage':
|
|
location = self.to_location.parent.storage_location
|
|
if self.product and location:
|
|
context = {
|
|
'location_ids': [location.id],
|
|
'stock_date_end': date.today(),
|
|
}
|
|
with Transaction().set_context(context):
|
|
res_dict = self.product._get_quantity(
|
|
[self.product],
|
|
'quantity',
|
|
[location.id],
|
|
grouping_filter=([self.product.id],)
|
|
)
|
|
if res_dict.get(self.product.id):
|
|
res += res_dict[self.product.id]
|
|
return res
|
|
|
|
|
|
class MoveByProductStart(ModelView):
|
|
'Move By Product Start'
|
|
__name__ = 'stock_co.move_by_product.start'
|
|
start_date = fields.Date('Start Date', required=True)
|
|
end_date = fields.Date('End Date', required=True)
|
|
from_location = fields.Many2One('stock.location', 'From Location')
|
|
to_location = fields.Many2One('stock.location', 'To Location',
|
|
required=True)
|
|
categories = fields.Many2Many('product.category', None, None, 'Categories')
|
|
company = fields.Many2One('company.company', 'Company',
|
|
required=True)
|
|
brand = fields.Many2One('product.brand', 'Brand')
|
|
party = fields.Many2One('party.party', 'Party')
|
|
shipment_draft = fields.Boolean('Shipment Draft')
|
|
start_time = fields.Time('Start Time',)
|
|
end_time = fields.Time('End Time', states={
|
|
'required': Bool(Eval('start_time')),
|
|
'invisible': Not(Bool(Eval('start_time'))),
|
|
}, depends=['start_time'])
|
|
product = fields.Many2One('product.product', 'Product')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@staticmethod
|
|
def default_end_date():
|
|
Date_ = Pool().get('ir.date')
|
|
return Date_.today()
|
|
|
|
@staticmethod
|
|
def default_start_date():
|
|
Date_ = Pool().get('ir.date')
|
|
return Date_.today()
|
|
|
|
|
|
class PrintMoveByProduct(Wizard):
|
|
'Move By Product'
|
|
__name__ = 'stock_co.print_move_by_product'
|
|
start = StateView('stock_co.move_by_product.start',
|
|
'stock_co.print_move_by_product_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-print', default=True),
|
|
])
|
|
print_ = StateReport('stock_co.move_by_product')
|
|
|
|
def do_print_(self, action):
|
|
category_ids = []
|
|
from_location_id = None
|
|
brand_id = None
|
|
party_id = None
|
|
start_time = None
|
|
end_time = None
|
|
|
|
if self.start.from_location:
|
|
from_location_id = self.start.from_location.id
|
|
if self.start.categories:
|
|
category_ids = [acc.id for acc in self.start.categories]
|
|
if self.start.brand:
|
|
brand_id = self.start.brand.id
|
|
if self.start.party:
|
|
party_id = self.start.party.id
|
|
if self.start.start_time:
|
|
start_time = self.start.start_time
|
|
if self.start.end_time:
|
|
end_time = self.start.end_time
|
|
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'from_location': from_location_id,
|
|
'to_location': self.start.to_location.id,
|
|
'start_date': self.start.start_date,
|
|
'end_date': self.start.end_date,
|
|
'categories': category_ids,
|
|
'brand': brand_id,
|
|
'party': party_id,
|
|
'shipment_draft': self.start.shipment_draft,
|
|
'start_time': start_time,
|
|
'end_time': end_time,
|
|
'product': self.start.product.id if self.start.product else None
|
|
}
|
|
return action, data
|
|
|
|
def transition_print_(self):
|
|
return 'end'
|
|
|
|
|
|
class MoveByProduct(Report):
|
|
'Move By Product Report'
|
|
__name__ = 'stock_co.move_by_product'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Company = pool.get('company.company')
|
|
Move = pool.get('stock.move')
|
|
Location = pool.get('stock.location')
|
|
Party = pool.get('party.party')
|
|
Brand = pool.get('product.brand')
|
|
Category = pool.get('product.template-product.category')
|
|
company = Company(data['company'])
|
|
from_location = None
|
|
brand_name = ''
|
|
party_name = ''
|
|
start_date = None
|
|
end_date = None
|
|
|
|
categories = Category.search([('category', 'in', data['categories'])])
|
|
|
|
products_ids = [c.template.id for c in categories]
|
|
dom_products = []
|
|
if data['start_time']:
|
|
start_date = datetime.combine(data['start_date'], data['start_time'])
|
|
end_date = datetime.combine(data['end_date'], data['end_time'])
|
|
|
|
_start_date = Company.convert_timezone(start_date, True)
|
|
_end_date = Company.convert_timezone(end_date, True)
|
|
dom_products.append(
|
|
('to_location.id', '=', data['to_location']),
|
|
('create_date', '>=', _start_date),
|
|
('create_date', '<=', _end_date)
|
|
)
|
|
else:
|
|
start_date = data['start_date']
|
|
end_date = data['end_date']
|
|
|
|
dom_products.extend([
|
|
('to_location', '=', data['to_location']),
|
|
['AND',
|
|
['OR', [
|
|
('planned_date', '>=', start_date),
|
|
('planned_date', '<=', end_date),
|
|
], [
|
|
('effective_date', '>=', start_date),
|
|
('effective_date', '<=', end_date),
|
|
],
|
|
]]
|
|
])
|
|
|
|
if data['shipment_draft']:
|
|
dom_products.append(('state', '=', 'draft'))
|
|
|
|
if data['from_location']:
|
|
dom_products.append(
|
|
('from_location.id', '=', data['from_location']),
|
|
)
|
|
from_location = Location(data['from_location'])
|
|
if data['categories']:
|
|
if products_ids:
|
|
dom_products.append(
|
|
('product.template', 'in', products_ids)
|
|
)
|
|
else:
|
|
dom_products.append(
|
|
('product.template.account_category', 'in', data['categories'])
|
|
)
|
|
if data['brand']:
|
|
dom_products.append(
|
|
('product.template.brand', '=', data['brand']),
|
|
)
|
|
brand_name = Brand(data['brand']).name
|
|
if data['party']:
|
|
dom_products.append(
|
|
('invoice_lines.invoice.party', '=', data['party']),
|
|
)
|
|
party_name = Party(data['party']).name
|
|
if data['product']:
|
|
dom_products.append(
|
|
('product', '=', data['product']),
|
|
)
|
|
moves = Move.search([dom_products])
|
|
|
|
products = {}
|
|
for move in moves:
|
|
product = move.product
|
|
amount = move.quantity * float(product.cost_price)
|
|
try:
|
|
row = products[product.id]
|
|
row[3].append(move.quantity)
|
|
row[5].append(amount)
|
|
except Exception as e:
|
|
template = product.template
|
|
brand = template.brand and template.brand.name
|
|
category = template.account_category and template.account_category.name
|
|
products[product.id] = [
|
|
product.code,
|
|
product.rec_name,
|
|
template.default_uom.symbol,
|
|
[move.quantity],
|
|
product.cost_price,
|
|
[amount],
|
|
category,
|
|
brand,
|
|
template.list_price,
|
|
]
|
|
|
|
report_context['records'] = products.values()
|
|
report_context['from_location'] = from_location
|
|
report_context['to_location'] = Location(data['to_location'])
|
|
report_context['start_date'] = start_date
|
|
report_context['end_date'] = end_date
|
|
report_context['company'] = company
|
|
report_context['brand_name'] = brand_name
|
|
report_context['party_name'] = party_name
|
|
return report_context
|
|
|
|
|
|
class WarehouseStockStart(ModelView):
|
|
'Warehouse Stock Start'
|
|
__name__ = 'stock_co.warehouse_stock.start'
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
locations = fields.Many2Many('stock.location', None, None, "Locations",
|
|
domain=[
|
|
('type', 'in', ['storage', 'customer']),
|
|
('active', '=', True)
|
|
], required=True)
|
|
to_date = fields.Date('To Date', required=True)
|
|
only_minimal_level = fields.Boolean('Only Minimal Level')
|
|
group_by_location = fields.Boolean('Group By Location')
|
|
group_by_supplier = fields.Boolean('Group By Supplier')
|
|
category = fields.Many2One('product.category', 'Category')
|
|
suppliers = fields.Many2Many('party.party', None, None, "Suppliers",
|
|
domain=[
|
|
('active', '=', True)
|
|
])
|
|
zero_quantity = fields.Boolean('Zero Quantity')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@staticmethod
|
|
def default_to_date():
|
|
Date_ = Pool().get('ir.date')
|
|
return Date_.today()
|
|
|
|
|
|
class WarehouseStock(Wizard):
|
|
'Warehouse Stock'
|
|
__name__ = 'stock_co.warehouse_stock'
|
|
start = StateView('stock_co.warehouse_stock.start',
|
|
'stock_co.warehouse_stock_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
print_ = StateReport('stock_co.warehouse_stock.report')
|
|
|
|
def do_print_(self, action):
|
|
category_id = None
|
|
if self.start.category:
|
|
category_id = self.start.category.id
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'locations': [l.id for l in self.start.locations],
|
|
'location_names': ', '.join([l.name for l in self.start.locations]),
|
|
'only_minimal_level': self.start.only_minimal_level,
|
|
'group_by_location': self.start.group_by_location,
|
|
'group_by_supplier': self.start.group_by_supplier,
|
|
'zero_quantity': self.start.zero_quantity,
|
|
'to_date': self.start.to_date,
|
|
'category': category_id,
|
|
'suppliers': [l.id for l in self.start.suppliers],
|
|
}
|
|
return action, data
|
|
|
|
|
|
class WarehouseReport(Report):
|
|
'Warehouse Report'
|
|
__name__ = 'stock_co.warehouse_stock.report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Company = pool.get('company.company')
|
|
Product = pool.get('product.product')
|
|
OrderPoint = pool.get('stock.order_point')
|
|
Location = pool.get('stock.location')
|
|
# ProductsSupplier = pool.get('purchase.product_supplier')
|
|
ids_location = data['locations']
|
|
locations = Location.browse(data['locations'])
|
|
dom_products = [
|
|
('active', '=', True),
|
|
('template.active', '=', True),
|
|
('type', '=', 'goods'),
|
|
('consumable', '=', False),
|
|
]
|
|
|
|
stock_context = {
|
|
'stock_date_end': data['to_date'],
|
|
'locations': ids_location,
|
|
}
|
|
|
|
if data['category']:
|
|
dom_products.append(['AND', ['OR', [
|
|
('account_category', '=', data['category']),
|
|
], [
|
|
('categories', 'in', [data['category']]),
|
|
],
|
|
]])
|
|
# dom_products.append(('account_category', '=', data['category']))
|
|
|
|
if not data['zero_quantity']:
|
|
dom_products.append([('quantity', '!=', 0)])
|
|
|
|
if data['only_minimal_level']:
|
|
order_points = OrderPoint.search([
|
|
('warehouse_location', 'in', ids_location),
|
|
('type', '=', 'purchase'),
|
|
])
|
|
min_quantities = {op.product.id: op.min_quantity for op in order_points}
|
|
|
|
products_ids = min_quantities.keys()
|
|
dom_products.append(('id', 'in', products_ids))
|
|
if data['suppliers']:
|
|
dom_products.append([('template.product_suppliers', 'in', data['suppliers'])])
|
|
|
|
total_amount = 0
|
|
values = {}
|
|
products = []
|
|
if data['group_by_location']:
|
|
for l in locations:
|
|
stock_context['locations'] = [l.id]
|
|
with Transaction().set_context(stock_context):
|
|
prdts = Product.search(dom_products, order=[('code', 'ASC')])
|
|
# p = [p.template.id for p in prdts]
|
|
# products_supplier = ProductsSupplier.search([
|
|
# ('template', 'in', p)])
|
|
suppliers = {}
|
|
if data['group_by_supplier']:
|
|
for p in prdts:
|
|
if not p.template.product_suppliers:
|
|
continue
|
|
sup = p.template.product_suppliers[0].party
|
|
sup_id = sup.id
|
|
try:
|
|
suppliers[sup_id]['products'].append(p)
|
|
suppliers[sup_id]['total_amount'].append(p.cost_value)
|
|
except:
|
|
suppliers[sup_id] = {}
|
|
suppliers[sup_id]['products'] = [p]
|
|
suppliers[sup_id]['party'] = sup
|
|
suppliers[sup_id]['total_amount'] = [p.cost_value]
|
|
total_amount = sum([p.cost_value for p in prdts if p.cost_value])
|
|
values[l.id] = {
|
|
'name': l.name,
|
|
'products': prdts,
|
|
'suppliers': suppliers.values(),
|
|
'total_amount': total_amount
|
|
}
|
|
products = values.values()
|
|
else:
|
|
with Transaction().set_context(stock_context):
|
|
products = Product.search(dom_products, order=[('code', 'ASC')])
|
|
|
|
if data['only_minimal_level']:
|
|
products = [p for p in products if p.quantity <= min_quantities[p.id]]
|
|
total_amount = sum([p.cost_value for p in products if p.cost_value])
|
|
suppliers = {}
|
|
if data['group_by_supplier']:
|
|
for p in products:
|
|
if not p.template.product_suppliers:
|
|
continue
|
|
sup = p.template.product_suppliers[0].party
|
|
sup_id = sup.id
|
|
try:
|
|
suppliers[sup_id]['products'].append(p)
|
|
suppliers[sup_id]['total_amount'].append(p.cost_value)
|
|
except:
|
|
suppliers[sup_id] = {}
|
|
suppliers[sup_id]['products'] = [p]
|
|
suppliers[sup_id]['party'] = sup
|
|
suppliers[sup_id]['total_amount'] = [p.cost_value]
|
|
products = suppliers.values()
|
|
|
|
cursor = Transaction().connection.cursor()
|
|
query = "select distinct on(p.id) p.id, t.name, p.code, s.effective_date from product_product as p right join stock_move as s on p.id=s.product join product_template as t on p.template=t.id where s.shipment ilike 'stock.shipment.in,%' and state='done' order by p.id, s.effective_date DESC;"
|
|
cursor.execute(query)
|
|
columns = list(cursor.description)
|
|
result = cursor.fetchall()
|
|
last_purchase = {}
|
|
|
|
for row in result:
|
|
row_dict = {}
|
|
for i, col in enumerate(columns):
|
|
row_dict[col.name] = row[i]
|
|
last_purchase[row[0]] = row_dict
|
|
|
|
report_context['group_by_location'] = data['group_by_location']
|
|
report_context['group_by_supplier'] = data['group_by_supplier']
|
|
report_context['records'] = products
|
|
report_context['total_amount'] = total_amount
|
|
report_context['last_purchase'] = last_purchase
|
|
report_context['location'] = data['location_names']
|
|
report_context['stock_date_end'] = data['to_date']
|
|
report_context['company'] = Company(data['company'])
|
|
return report_context
|
|
|
|
|
|
class PrintProductsStart(ModelView):
|
|
'Products Start'
|
|
__name__ = 'stock_co.print_products.start'
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
category = fields.Many2One('product.category', 'Category')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
|
|
class PrintProducts(Wizard):
|
|
'Warehouse Stock'
|
|
__name__ = 'stock_co.print_products'
|
|
start = StateView('stock_co.print_products.start',
|
|
'stock_co.print_products_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
print_ = StateReport('stock_co.print_products.report')
|
|
|
|
def do_print_(self, action):
|
|
category_id = None
|
|
if self.start.category:
|
|
category_id = self.start.category.id
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'category': category_id,
|
|
}
|
|
return action, data
|
|
|
|
|
|
class PrintProductsReport(Report):
|
|
'Warehouse Report'
|
|
__name__ = 'stock_co.print_products.report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Company = pool.get('company.company')
|
|
Product = pool.get('product.product')
|
|
Date_ = Pool().get('ir.date')
|
|
dom_products = [
|
|
('active', '=', True),
|
|
('type', '=', 'goods'),
|
|
('consumable', '=', False),
|
|
]
|
|
|
|
if data['category']:
|
|
dom_products.append(('account_category', '=', data['category']))
|
|
|
|
products = Product.search(dom_products, order=[('code', 'ASC')])
|
|
|
|
report_context['records'] = products
|
|
report_context['stock_date_end'] = Date_.today()
|
|
report_context['company'] = Company(data['company'])
|
|
return report_context
|
|
|
|
|
|
class WarehouseStockDetailedStart(ModelView):
|
|
'Warehouse Stock Detailed Start'
|
|
__name__ = 'stock_co.warehouse_stock_detailed.start'
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
locations = fields.Many2Many('stock.location', None, None, "Locations",
|
|
domain=[
|
|
('id', 'in', Eval('location_storage')),
|
|
('active', '=', True)
|
|
], depends=['location_storage'])
|
|
location_storage = fields.One2Many('stock.location', None, 'Locations Storage')
|
|
to_date = fields.Date('To Date', required=True)
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@staticmethod
|
|
def default_to_date():
|
|
Date_ = Pool().get('ir.date')
|
|
return Date_.today()
|
|
|
|
@staticmethod
|
|
def default_location_storage():
|
|
Location = Pool().get('stock.location')
|
|
locations = Location.search([('type', '=', 'warehouse')])
|
|
return [l.storage_location.id for l in locations if l.storage_location.id]
|
|
|
|
|
|
class WarehouseStockDetailed(Wizard):
|
|
'Warehouse Stock Detailed'
|
|
__name__ = 'stock_co.warehouse_stock_detailed'
|
|
start = StateView('stock_co.warehouse_stock_detailed.start',
|
|
'stock_co.warehouse_stock_detailed_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
|
|
print_ = StateReport('stock_co.warehouse_stock_detailed.report')
|
|
|
|
def do_print_(self, action):
|
|
location_ids = None
|
|
if self.start.locations:
|
|
location_ids = [l.id for l in self.start.locations]
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'locations': location_ids,
|
|
'to_date': self.start.to_date,
|
|
}
|
|
return action, data
|
|
|
|
|
|
class WarehouseStockDetailedReport(Report):
|
|
'Warehouse Stock Detailed Report'
|
|
__name__ = 'stock_co.warehouse_stock_detailed.report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Company = pool.get('company.company')
|
|
Product = pool.get('product.product')
|
|
Location = pool.get('stock.location')
|
|
if data['locations']:
|
|
ids_location = data['locations']
|
|
locations = Location.browse(ids_location)
|
|
else:
|
|
locations = Location.search([
|
|
('type', '=', 'warehouse')
|
|
])
|
|
ids_location = [l.storage_location.id for l in locations if l.storage_location]
|
|
dom_products = [
|
|
('active', '=', True),
|
|
('template.active', '=', True),
|
|
('type', '=', 'goods'),
|
|
('consumable', '=', False),
|
|
]
|
|
|
|
stock_context = {
|
|
'stock_date_end': data['to_date'],
|
|
'locations': ids_location,
|
|
}
|
|
# dom_products.append(('account_category', '=', data['category']))
|
|
|
|
cursor = Transaction().connection.cursor()
|
|
query = "select distinct on(p.id) p.id, t.name, p.code, t.reference, s.effective_date from product_product as p right join stock_move as s on p.id=s.product join product_template as t on p.template=t.id where s.shipment ilike 'stock.shipment.in,%' and state='done' order by p.id, s.effective_date DESC"
|
|
cursor.execute(query)
|
|
columns = list(cursor.description)
|
|
result = cursor.fetchall()
|
|
last_purchase = {}
|
|
|
|
for row in result:
|
|
row_dict = {}
|
|
for i, col in enumerate(columns):
|
|
row_dict[col.name] = row[i]
|
|
last_purchase[row[0]] = row_dict
|
|
|
|
values = []
|
|
add_ = values.append
|
|
for l in locations:
|
|
stock_context['locations'] = [l.id]
|
|
with Transaction().set_context(stock_context):
|
|
prdts = Product.search(dom_products, order=[('code', 'ASC')])
|
|
for p in prdts:
|
|
add_({
|
|
'parent_name': l.parent.name if l.parent else '',
|
|
'name': l.name,
|
|
'product': p,
|
|
})
|
|
|
|
products = values
|
|
report_context['records'] = products
|
|
report_context['Decimal'] = Decimal
|
|
report_context['last_purchase'] = last_purchase
|
|
report_context['stock_date_end'] = data['to_date']
|
|
report_context['company'] = Company(data['company'])
|
|
return report_context
|
|
|
|
|
|
class WarehouseKardexStockStart(ModelView):
|
|
'Warehouse Kardex Stock Start'
|
|
__name__ = 'stock_co.warehouse_kardex_stock.start'
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
location = fields.Many2One('stock.location', "Location",
|
|
domain=[
|
|
('type', 'in', ['warehouse']),
|
|
('active', '=', True)
|
|
], required=True)
|
|
from_date = fields.Date('From Date', required=True)
|
|
to_date = fields.Date('To Date', required=True)
|
|
categories = fields.Many2Many('product.category', None, None, 'Categories')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@staticmethod
|
|
def default_to_date():
|
|
Date_ = Pool().get('ir.date')
|
|
return Date_.today()
|
|
|
|
|
|
class WarehouseKardexStock(Wizard):
|
|
'Warehouse Kardex Stock'
|
|
__name__ = 'stock_co.warehouse_kardex_stock'
|
|
start = StateView('stock_co.warehouse_kardex_stock.start',
|
|
'stock_co.warehouse_kardex_stock_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
print_ = StateReport('stock_co.warehouse_kardex_stock.report')
|
|
|
|
def do_print_(self, action):
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'location': self.start.location.id,
|
|
'from_date': self.start.from_date,
|
|
'to_date': self.start.to_date,
|
|
'categories': [l.id for l in self.start.categories],
|
|
}
|
|
return action, data
|
|
|
|
|
|
class WarehouseKardexReport(Report):
|
|
'Warehouse Kardex Report'
|
|
__name__ = 'stock_co.warehouse_kardex_stock.report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Company = pool.get('company.company')
|
|
Product = pool.get('product.product')
|
|
Location = pool.get('stock.location')
|
|
warehouse = Location(data['location'])
|
|
# StockMove = pool.get('stock.move')
|
|
id_location = warehouse.storage_location.id
|
|
input_location = warehouse.input_location.id
|
|
output_location = warehouse.output_location.id
|
|
dom_products = [
|
|
('active', '=', True),
|
|
('template.active', '=', True),
|
|
('type', '=', 'goods'),
|
|
('consumable', '=', False),
|
|
]
|
|
if data['categories']:
|
|
dom_products.append(['AND', ['OR', [
|
|
('account_category', 'in', data['categories']),
|
|
], [
|
|
('categories', 'in', data['categories']),
|
|
],
|
|
]])
|
|
|
|
stock_context_start = {
|
|
'stock_date_end': (data['from_date'] - timedelta(1)),
|
|
'locations': [id_location],
|
|
}
|
|
stock_context_end = {
|
|
'stock_date_end': data['to_date'],
|
|
'locations': [id_location],
|
|
}
|
|
|
|
fields_names = ['code', 'name', 'reference', 'quantity']
|
|
with Transaction().set_context(stock_context_start):
|
|
products_start = Product.search_read(dom_products, fields_names=fields_names, order=[('code', 'ASC')])
|
|
|
|
with Transaction().set_context(stock_context_end):
|
|
products_end = Product.search_read(dom_products, fields_names=fields_names, order=[('code', 'ASC')])
|
|
|
|
products = [p['id'] for p in products_start]
|
|
|
|
type = {'input': f'and from_location != {output_location} and to_location = {id_location}',
|
|
'input_dif': f'and from_location = {id_location} and to_location = {input_location}',
|
|
'output': f'and from_location = {id_location} and to_location != {output_location}',
|
|
'output_dif': f'and from_location = {output_location} and to_location = {id_location}'}
|
|
|
|
moves = {}
|
|
for k, v in type.items():
|
|
clause = v
|
|
query = f"""select product, sum(quantity) as quantity from stock_move
|
|
where product in {tuple(products)}
|
|
and effective_date >= '{str(data['from_date'])}'
|
|
and effective_date <= '{str(data['to_date'])}'
|
|
{clause}
|
|
group by product;"""
|
|
moves[k] = cls.query_to_dict(query)
|
|
|
|
for m, v in moves.items():
|
|
if not m.endswith('dif'):
|
|
continue
|
|
|
|
for k, value in v.items():
|
|
move = moves[m[0:-4]].get(k, None)
|
|
quantity = 0
|
|
if move:
|
|
quantity = move['quantity']
|
|
moves[m[0:-4]][k] = quantity - value['quantity']
|
|
|
|
report_context['products_out'] = moves['output']
|
|
report_context['products_in'] = moves['input']
|
|
report_context['products_start'] = products_start
|
|
report_context['products_end'] = products_end
|
|
report_context['products'] = products
|
|
report_context['warehouse'] = warehouse.name
|
|
report_context['company'] = Company(data['company'])
|
|
return report_context
|
|
|
|
@classmethod
|
|
def query_to_dict(cls, query):
|
|
cursor = Transaction().connection.cursor()
|
|
cursor.execute(query)
|
|
columns = list(cursor.description)
|
|
result = cursor.fetchall()
|
|
res_dict = {}
|
|
for row in result:
|
|
row_dict = {}
|
|
for i, col in enumerate(columns):
|
|
row_dict[col.name] = row[i]
|
|
res_dict[row[0]] = row_dict
|
|
return res_dict
|