trytonpsk-sale_pos_frontend.../sale.py
Oscar Alvarez 45343dcd89 Minor fix
2021-01-21 14:35:43 -05:00

362 lines
14 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 __future__ import unicode_literals
from datetime import date, datetime
from trytond.pool import PoolMeta, Pool
from trytond.model import fields
from trytond.pyson import Eval
from trytond.transaction import Transaction
from trytond.wizard import Wizard
__all__ = ['Sale', 'Shop']
KIND = [
('', ''),
('take_away', 'Take Away'),
('delivery', 'Delivery'),
('to_table', 'To Table')
]
class Sale(metaclass=PoolMeta):
__name__ = 'sale.sale'
consumer = fields.Many2One('party.consumer', 'Consumer')
table_assigned = fields.Many2One('sale.shop.table', 'Table Assigned',
domain=[
('shop', '=', Eval('shop')),
])
productions = fields.Function(fields.One2Many('production', None, 'Productions'), 'get_productions')
delivery_time = fields.Numeric('Delivery Time (Min)', help="In Minutes")
order_status = fields.Selection([
('', ''),
('draft', 'Draft'),
('commanded', 'Commanded'),
('in_preparation', 'In Preparation'),
('dispatched', 'Dispatched'),
('delivered', 'Delivered'),
('rejected', 'Rejected'),
('cancelled', 'Cancelled'),
], 'Order Status')
order_status_string = order_status.translated('order_status')
shipping_time = fields.DateTime('Shipping Time')
waiting_time = fields.Function(fields.Integer('Shipping Time',
help="In Minutes"), 'get_waiting_time')
@classmethod
def __setup__(cls):
super(Sale, cls).__setup__()
cls._error_messages.update({
'product_without_bom': (
"The product '%(product)s' has no production bom"),
'message_error': 'Error: %s',
},)
@staticmethod
def default_order_status():
return 'draft'
def get_waiting_time(self, name=None):
now = datetime.now()
if self.state in ('draft', 'quotation', 'confirmed', 'processing'):
delta = int((now - self.create_date).seconds / 60)
return delta
@classmethod
def import_data(cls, fields_names, data):
pool = Pool()
Product = pool.get('product.product')
Party = pool.get('party.party')
Address = pool.get('party.address')
SaleLine = pool.get('sale.line')
Journal = pool.get('account.statement.journal')
config = pool.get('sale.configuration')(1)
user_ = pool.get('res.user')(Transaction().user)
shop_id = user_.shop.id
device_id = user_.sale_device.id
count = 0
sale_to_create = {}
sale_tip_product = {}
create_lines = []
sales_to_pay = []
tip_product = None
if config:
tip_product = config.tip_product.id
for row in data[1:]:
code_ = row[3].replace(' ', '')
products = Product.search([
('code', '=', code_)
])
if not products:
cls.raise_user_error('message_error',
('No se encontro un producto para el código: ' + row[3])
)
product = products[0]
if not product.salable:
print(product.code, product.name)
# day, month, year = row[2].split('/')
# sale_date = date(int(year), int(month), int(day))
# partys = Party.search([
# ('id_number', '=', row[1])
# ])
# if not partys:
# cls.raise_user_error('message_error',
# ('No se encontro un tercero para el documento: ' + row[1]))
# party = partys[0]
# if row[0] not in sale_to_create.keys():
# # with Transaction().set_context(ctx):
# sale, = cls.create([{
# 'sale_date': sale_date,
# 'party': party.id,
# 'number': row[0],
# 'payment_term': 1,
# 'shop': shop_id,
# 'sale_device': device_id,
# 'invoice_address': party.address_get(type='invoice'),
# 'shipment_address': party.address_get(type='delivery'),
# }])
# sale.on_change_party()
# sale.save()
# sale_to_create[row[0]] = sale.id
# journals = Journal.search_read([
# ('name', '=', row[11])
# ], fields_names=['id'])
# if not journals:
# cls.raise_user_error('message_error',
# ('No se encontro un libro con el nombre ' + row[11])
# )
# sales_to_pay.append({
# 'sale': sale,
# 'journal_id': journals[0]['id']
# })
# count += 1
# # print(count, row[0])
#
# sale_id = sale_to_create[row[0]]
# code_ = row[3].replace(' ', '')
# products = Product.search([
# ('code', '=', code_)
# ])
#
# if not products:
# cls.raise_user_error('message_error',
# ('No se encontro un producto para el código: ' + row[3])
# )
# product = products[0]
# if not product.salable:
# product.template.write([product.template], {'salable': True})
# print('No vendible en lista')
# print(product.code, product.name)
# line = {
# 'sale': sale_id,
# 'product': product.id,
# 'quantity': row[5],
# 'description': row[4],
# 'unit_digits': product.sale_uom.digits,
# 'unit': product.sale_uom,
# 'unit_price': Decimal(row[6]),
# 'discount': Decimal(row[7]),
# 'taxes': [('add', product.customer_taxes_used)],
# }
# SaleLine.create([line])
# if if row[0] not in sale_tip_product.keys() and row[10] and tip_product:
# create_lines.append({
# 'sale': sale_id,
# 'product': tip_product,
# 'quantity': 1,
# 'description': "PROPINA",
# 'unit': 1,
# 'unit_price': Decimal(row[10]),
# 'discount': Decimal('0.00'),
# })
# sale_tip_product[row[0]] = row[10]
# if not row[11]:
# cls.raise_user_error('message_error',
# ('el campo medio de pago es obligatorio')
# )
#
# cls.transition_pay_(sales_to_pay)
return count
@classmethod
def transition_pay_(cls, sales_to_pay):
pool = Pool()
Statement = pool.get('account.statement')
StatementLine = pool.get('account.statement.line')
for sale_pay in sales_to_pay:
sale = sale_pay['sale']
journal_id = sale_pay['journal_id']
statements = Statement.search([
('journal', '=', journal_id),
('state', '=', 'draft'),
('sale_device', '=', sale.sale_device),
], order=[('date', 'DESC')])
if not statements:
cls.raise_user_error(
'message_error',
'A draft statement payments has not been created.'
)
if not sale.number:
cls.set_number([sale])
account = (sale.party.account_receivable and sale.party.account_receivable.id
or cls.raise_user_error('message_error', 'Party %s has no any \
account receivable defined. Please, assign one.' % (sale.party.name)))
payment = StatementLine(
statement=statements[0].id,
date=date.today(),
amount=sale.total_amount,
party=sale.party.id,
account=account,
description=sale.number,
sale=sale.id,
)
payment.save()
sale.save()
cls.workflow_to_end([sale])
@classmethod
def update_consumer(cls, args, context):
Consumer = Pool().get('party.consumer')
fields = args['fields']
consumer = Consumer(args['id'])
for key, value in fields.items():
if hasattr(consumer, key):
Consumer.write([consumer], {key: value})
return cls._get_object(consumer)
@classmethod
def create_consumer(cls, args, context):
Consumer = Pool().get('party.consumer')
consumer = None
notes = ''
if args.get('fields'):
fields = args['fields']
consumer, = Consumer.create([fields])
if consumer and consumer.party:
party = consumer.party
party.write([party], {'notes': notes})
return cls._get_object(consumer)
return {
'msg': 'ok',
'consumer': {
'id': consumer.id,
'name': consumer.name,
'phone': consumer.phone,
'address': consumer.address or '',
'notes': consumer.notes,
}
}
@classmethod
def _get_object(cls, consumer):
obj_ = {
'msg': 'ok',
'party': None,
'consumer': {
'id': consumer.id,
'name': consumer.name,
'phone': consumer.phone,
'address': consumer.address or '',
'notes': consumer.notes or '',
},
}
if consumer.party:
obj_['party'] = consumer.party.id
return obj_
@classmethod
def _create_productions(cls, lines):
pool = Pool()
Production = pool.get('production')
Location = pool.get('stock.location')
Bom = pool.get('production.bom')
for line in lines:
if line.production:
return
if line.product.producible:
boms = Bom.search_read([
('output_products', '=', line.product.id)
], fields_names=['id'])
if not boms:
continue
warning_name = '%s.product.without_bom' % line
cls.raise_user_warning(
warning_name, 'product_without_bom', {
'product': line.product.rec_name,
})
else:
bom_ = boms[0]
locations = Location.search_read([
('type', '=', 'production'),
], fields_names=['id'])
location_ = locations[0] if locations else None
sale = line.sale
date_ = sale.sale_date
product_ = line.product
create_production = {
'reference': sale.number,
'planned_date': date_,
'effective_date': date_,
'planned_start_date': date_,
'effective_start_date': date_,
'company': sale.company.id,
'warehouse': sale.warehouse.id,
'location': location_['id'],
'product': product_.id,
'uom': product_.default_uom.id,
'unit_digits': product_.default_uom.digits,
'state': 'draft',
}
production, = Production.create([create_production])
production.bom = bom_['id']
production.quantity = line.quantity
production.on_change_quantity()
production.save()
Production.wait([production])
Production.assign([production])
Production.run([production])
Production.done([production])
line.production = production.id
line.save()
def get_productions(self, name):
productions = []
for line in self.lines:
if line.production:
productions.append(line.production)
return productions
class SaleForceDraft(Wizard):
__name__ = 'sale_pos.force_draft'
def transition_force_draft(self):
pool = Pool()
Sale = pool.get('sale.sale')
Production = pool.get('production')
ids = Transaction().context['active_ids']
if not ids:
return 'end'
for sale in Sale.browse(ids):
for p in sale.productions:
cursor = Transaction().connection.cursor()
cursor.execute("UPDATE production SET state='waiting' WHERE id in (%s)" % (p.id))
Production.draft([p])
Production.cancel([p])
Production.delete([p])
return super(SaleForceDraft, self).transition_force_draft()
class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line'
production = fields.Many2One('production', 'Production')
class Shop(metaclass=PoolMeta):
__name__ = 'sale.shop'
tables = fields.One2Many('sale.shop.table', 'shop', 'Tables')