387 lines
13 KiB
Python
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'
|