trytonpsk-stock_co/shipment.py

387 lines
13 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
from decimal import Decimal
from operator import itemgetter
from sql import Table
from trytond.pool import Pool, PoolMeta
from trytond.wizard import Wizard, StateTransition, StateView, Button, StateReport
from trytond.transaction import Transaction
from trytond.model import ModelView, fields
from trytond.report import Report
from trytond.pyson import Eval
type_shipment = {
'out': 'Envio a Clientes',
'in': 'Envio de Proveedor',
'internal': 'Envio Interno',
}
class ShipmentIn(metaclass=PoolMeta):
'Shipment In'
__name__ = 'stock.shipment.in'
@classmethod
def __setup__(cls):
super(ShipmentIn, cls).__setup__()
cls.reference.states = {
'required': Eval('state').in_(['received']),
}
class InternalShipment(metaclass=PoolMeta):
'Internal Shipment'
__name__ = 'stock.shipment.internal'
# location_storage = fields.One2Many('stock.location', None, 'Locations Storage')
@classmethod
def __setup__(cls):
super(InternalShipment, cls).__setup__()
# cls.from_location.depends = ['location_storage']
cls.from_location.domain = [
('name', 'ilike', 'ZA%'),
('active', '=', True)
]
# cls.to_location.depends = ['location_storage']
cls.to_location.domain = [
('name', 'ilike', 'ZA%'),
('active', '=', True)
]
# @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]
@classmethod
def wait(cls, shipments):
super(InternalShipment, cls).wait(shipments)
cls.set_employee(shipments, 'shipped_by')
@classmethod
def done(cls, shipments):
super(InternalShipment, cls).done(shipments)
cls.set_employee(shipments, 'done_by')
@classmethod
def set_employee(cls, shipments, field):
employee_id = Transaction().context.get('employee')
if employee_id:
cls.write(shipments, {field: employee_id})
@classmethod
def import_data(cls, fields_names, data):
pool = Pool()
Move = pool.get('stock.move')
Location = pool.get('stock.location')
Product = pool.get('product.product')
count = 0
head = data[0]
from_ = head[1]
to_ = head[2]
shp_date = head[0]
year, month, day = shp_date.split('-')
date_ = date(int(year), int(month), int(day))
from_locations = Location.search([
('code', '=', from_),
('type', 'in', ['view', 'storage', 'lost_found'])
])
to_locations = Location.search([
('code', '=', to_),
('type', 'in', ['view', 'storage', 'lost_found'])
])
if not from_locations or not to_locations:
return count
else:
from_location_id = from_locations[0].id
to_location_id = to_locations[0].id
shipment, = cls.create([{
'effective_date': date_,
'planned_date': date_,
'planned_start_date': date_,
'from_location': from_location_id,
'to_location': to_location_id,
'state': 'draft',
}])
moves_to_create = []
for row in data[1:]:
count += 1
products = Product.search([
('code', '=', row[0])
])
uom_id = products[0].template.default_uom.id
moves_to_create.append({
'product': products[0].id,
'uom': uom_id,
'quantity': int(row[1]),
'internal_quantity': int(row[1]),
'from_location': from_location_id,
'to_location': to_location_id,
'shipment': str(shipment),
'state': 'draft',
})
Move.create(moves_to_create)
return count
class CreateInternalShipmentStart(ModelView):
'Create Internal Shipment Start'
__name__ = 'stock_co.create_internal_shipment.start'
from_location = fields.Many2One('stock.location', "From Location",
required=True, domain=[
('type', 'in', ['view', 'storage', 'lost_found']),
])
to_location = fields.Many2One('stock.location', "To Location",
required=True, domain=[
('type', 'in', ['view', 'storage', 'lost_found']),
])
class CreateInternalShipment(Wizard):
'Create Internal Shipment'
__name__ = 'stock_co.create_internal_shipment'
start = StateView('stock_co.create_internal_shipment.start',
'stock_co.create_internal_shipment_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'accept', 'tryton-ok', default=True),
])
accept = StateTransition()
def transition_accept(self):
pool = Pool()
Internal = pool.get('stock.shipment.internal')
ShipmentSupplier = pool.get('stock.shipment.in')
shipment_id = Transaction().context.get('active_id')
shipment_supplier = ShipmentSupplier(shipment_id)
moves_target = []
today = date.today()
for move in shipment_supplier.incoming_moves:
moves_target.append({
'product': move.product.id,
'uom': move.product.default_uom.id,
'quantity': move.quantity,
'internal_quantity': move.quantity,
'from_location': self.start.from_location.id,
'to_location': self.start.to_location.id,
'planned_date': today,
'effective_date': today,
'state': 'draft',
})
data = {
'company': shipment_supplier.company.id,
'effective_date': today,
'planned_date': today,
'effective_start_date': today,
'planned_start_date': today,
'from_location': self.start.from_location.id,
'to_location': self.start.to_location.id,
'state': 'draft',
'moves': [('create', moves_target)],
}
Internal.create([data])
return 'end'
class ShipmentOutForceDraft(Wizard):
'Shipment Out Force Draft'
__name__ = 'stock.shipment.out.force_draft'
start_state = 'force_draft'
force_draft = StateTransition()
def transition_force_draft(self):
id_ = Transaction().context['active_id']
Shipment = Pool().get('stock.shipment.out')
stock_move = Table('stock_move')
if id_:
shipment = Shipment(id_)
cursor = Transaction().connection.cursor()
for rec in shipment.inventory_moves:
cursor.execute(*stock_move.delete(
where=stock_move.id == rec.id)
)
for rec in shipment.outgoing_moves:
cursor.execute(*stock_move.update(
columns=[stock_move.state],
values=['draft'],
where=stock_move.id == rec.id)
)
shipment.state = 'draft'
shipment.save()
return 'end'
class ShipmentInternalForceDraft(Wizard):
'Shipment Internal Force Draft'
__name__ = 'stock.shipment.internal.force_draft'
start_state = 'force_draft'
force_draft = StateTransition()
def transition_force_draft(self):
id_ = Transaction().context['active_id']
Shipment = Pool().get('stock.shipment.internal')
stock_move = Table('stock_move')
if id_:
shipment = Shipment(id_)
cursor = Transaction().connection.cursor()
for rec in shipment.moves:
cursor.execute(*stock_move.update(
columns=[stock_move.state],
values=['draft'],
where=stock_move.id == rec.id)
)
shipment.state = 'draft'
shipment.save()
return 'end'
class ShipmentDetailedStart(ModelView):
'Shipment Detailed Start'
__name__ = 'stock.shipment.shipment_detailed.start'
company = fields.Many2One('company.company', 'Company', required=True)
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
type_shipment = fields.Selection([
('in', 'Supplier'),
('out', 'Customer'),
('internal', 'Internal'),
], 'Type Shipment', required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class ShipmentDetailed(Wizard):
'Shipment Detailed'
__name__ = 'stock.shipment.shipment_detailed'
start = StateView('stock.shipment.shipment_detailed.start',
'stock_co.print_shipment_detailed_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('stock.shipment.shipment_detailed.report')
def do_print_(self, action):
data = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'type_shipment': self.start.type_shipment,
}
return action, data
def transition_print_(self):
return 'end'
class ShipmentDetailedReport(Report):
'Shipment Detailed Report'
__name__ = 'stock.shipment.shipment_detailed.report'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
company = Transaction().context.get('company.rec_name')
model = 'stock.shipment.' + data['type_shipment']
ModelShipment = pool.get(model)
Move = pool.get('stock.move')
Product = pool.get('product.product')
dom_shipment = [
('company', '=', data['company']),
('effective_date', '>=', data['start_date']),
('effective_date', '<=', data['end_date'])
]
fields_names = ['id']
shipments = ModelShipment.search_read(dom_shipment,
fields_names=fields_names,
order=[('effective_date', 'ASC')]
)
shipments = [model + ',' + str(sh['id']) for sh in shipments]
fields_names = [
'product.account_category.name', 'product.name', 'product.cost_price',
'quantity',
]
moves = Move.search_read(
('shipment', 'in', shipments),
fields_names=fields_names
)
dgetter = itemgetter('product.', 'quantity')
product_browse = Product.browse
for m in moves:
product, quantity = dgetter(m)
product_, = product_browse([product['id']])
try:
# FIXME
# oc = s.to_location.parent.operation_center.name
pass
except:
oc = ''
cost_price = product['cost_price']
category = product.get('account_category.', '')
if category:
category = category['name']
m.update({
'oc': '',
'product': product['name'],
'cost_price': cost_price,
'category': category,
'cost_base': float(cost_price) * quantity,
'cost_w_tax': float(product_.cost_price_taxed) * quantity,
})
report_context['records'] = moves
report_context['company'] = company
report_context['Decimal'] = Decimal
report_context['kind'] = type_shipment[data['type_shipment']]
return report_context
class Assign(metaclass=PoolMeta):
"Assign Shipment"
__name__ = 'stock.shipment.assign'
split = StateTransition()
@classmethod
def __setup__(cls):
super(Assign, cls).__setup__()
cls.partial.buttons.append(Button('Split', 'split', 'tryton-ok'))
def transition_split(self):
self.split_shipment()
return 'end'
def split_shipment(self):
pool = Pool()
Move = pool.get('stock.move')
Shipment = pool.get(Transaction().context.get('active_model'))
shipment = Shipment(Transaction().context.get('active_id'))
number_reference = shipment.number
if Shipment.__name__ == 'stock.shipment.out':
Move.draft(shipment.inventory_moves)
Move.delete(
[m for m in shipment.inventory_moves if m.state == 'draft'])
shipment, = Shipment.copy([shipment], default={'moves': None})
Shipment.write([shipment], {'reference': number_reference})
Move.write(list(self.partial.moves), {'shipment': str(shipment)})
return 'end'