934 lines
34 KiB
Python
934 lines
34 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, timedelta
|
|
from sql import Table
|
|
from trytond.pool import PoolMeta, Pool
|
|
from trytond.model import fields, ModelSQL, ModelView
|
|
from trytond.modules.product import price_digits
|
|
from trytond.pyson import Eval
|
|
from trytond.transaction import Transaction
|
|
from trytond.wizard import (
|
|
Wizard, StateView, Button, StateReport
|
|
)
|
|
from operator import attrgetter
|
|
from decimal import Decimal
|
|
from trytond.report import Report
|
|
from trytond.i18n import gettext
|
|
from .exceptions import (PayValidationError, ProductionValidationWarning,
|
|
DeleteSaleError)
|
|
from trytond.modules.sale_pos_frontend.sale import SaleSquareBox
|
|
|
|
KIND = [
|
|
('', ''),
|
|
('take_away', 'Take Away'),
|
|
('delivery', 'Delivery'),
|
|
('to_table', 'To Table')
|
|
]
|
|
|
|
OPTIONS_STATUS = [
|
|
('', ''),
|
|
('draft', 'Draft'),
|
|
('requested', 'Requested'),
|
|
('commanded', 'Commanded'),
|
|
('in_preparation', 'In Preparation'),
|
|
('dispatched', 'Dispatched'),
|
|
('delivered', 'Delivered'),
|
|
('rejected', 'Rejected'),
|
|
('cancelled', 'Cancelled'),
|
|
]
|
|
|
|
|
|
class SaleMove(ModelSQL):
|
|
"Sale - Stock Move"
|
|
__name__ = "sale.sale-stock.move"
|
|
_table = 'sale_sale-stock_move_rel'
|
|
sale = fields.Many2One('sale.sale', 'Sale',
|
|
ondelete='CASCADE', select=True, required=True)
|
|
move = fields.Many2One('stock.move', 'Stock Move',
|
|
ondelete='CASCADE', select=True, required=True)
|
|
|
|
|
|
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')
|
|
production_moves = fields.Many2Many('sale.sale-stock.move', 'sale', 'move', 'Production Moves')
|
|
order_status = fields.Selection(OPTIONS_STATUS, 'Order Status')
|
|
order_status_string = order_status.translated('order_status')
|
|
# delivery_time = fields.Numeric('Delivery Time (Min)', help="In Minutes")
|
|
# shipping_time = fields.DateTime('Shipping Time')
|
|
waiting_time = fields.Function(fields.Integer('Shipping Time',
|
|
help="In Minutes"), 'get_waiting_time')
|
|
order_status_time = fields.Many2One('sale.order_status.time', string='Times Order Status')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Sale, cls).__setup__()
|
|
|
|
@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 mark_commanded(cls, args):
|
|
"""
|
|
This method mark as commanded all products in sale, previous
|
|
positive response of local printer
|
|
"""
|
|
Status = Pool().get('sale.order_status.time')
|
|
Line = Pool().get('sale.line')
|
|
lines_ = args.get('lines_ids', [])
|
|
|
|
if args.get('sale_id'):
|
|
sale = cls(args['sale_id'])
|
|
sales = [sale]
|
|
else:
|
|
lines = Line.browse(lines_)
|
|
sales = set(ln.sale for ln in lines)
|
|
for sale in sales:
|
|
to_write = {'order_status': 'commanded'}
|
|
now = datetime.now()
|
|
order_time = sale.order_status_time
|
|
if order_time:
|
|
Status.write([order_time], {'commanded': now})
|
|
else:
|
|
status, = Status.create([{'commanded': now, 'requested': now, 'sale': sale.id}])
|
|
to_write['order_status_time'] = status
|
|
cls.write([sale], to_write)
|
|
if args.get('lines_ids'):
|
|
lines_ids = args['lines_ids']
|
|
lines = Line.browse(lines_ids)
|
|
Line.write(list(lines), {'order_sended': True, 'status_order': 'commanded'})
|
|
|
|
@classmethod
|
|
def do(cls, sales):
|
|
if sales:
|
|
ShopTable = Pool().get('sale.shop.table')
|
|
tables = ShopTable.search([('sale', 'in', [s.id for s in sales])])
|
|
if tables:
|
|
ShopTable.write(tables, {'sale': None, 'state': 'available'})
|
|
|
|
@classmethod
|
|
def get_orders_to_command(cls, args):
|
|
# function deprecated for remove
|
|
pool = Pool()
|
|
Line = pool.get('sale.line')
|
|
shop = args['shop']
|
|
|
|
_date = str(datetime.now() - timedelta(hours=1))
|
|
fields = [
|
|
'sale.number', 'quantity', 'note',
|
|
'product.tasks.printers.shop',
|
|
'product.tasks.printers.name',
|
|
'product.tasks.printers.host',
|
|
'product.tasks.printers.interface',
|
|
'product.tasks.printers.port',
|
|
'product.tasks.printers.row_characters',
|
|
'product.tasks.name']
|
|
dom = [
|
|
("sale.shop", "=", shop),
|
|
("sale.state", "in", ("draft", "quotation")),
|
|
("status_order", "=", 'requested'),
|
|
("create_date", ">=", _date),
|
|
]
|
|
|
|
if args.get('sale_id'):
|
|
dom.append(('sale', '=', args['sale']))
|
|
lines = Line.search_read(
|
|
dom, fields_names=fields,
|
|
order=[('sale', 'ASC')])
|
|
|
|
data = {}
|
|
for line in lines:
|
|
sale_id = line['sale.']['id']
|
|
sale_number = line['sale.']['number']
|
|
qty = line['quantity']
|
|
note = line['note']
|
|
id_ = str(line['id'])
|
|
|
|
try:
|
|
data[sale_id]
|
|
except Exception:
|
|
data[sale_id] = {
|
|
'id': sale_id,
|
|
'tasks': {},
|
|
'orders': []
|
|
}
|
|
|
|
for t in line['product.']['tasks.']:
|
|
line_ = {
|
|
'quantity': qty, 'note': note,
|
|
'name': t['name'], 'line': id_,
|
|
'task': str(t['id'])}
|
|
for p in t['printers.']:
|
|
key = str(p['id'])
|
|
if p['shop'] == shop:
|
|
value = {
|
|
**line_,
|
|
'printer': p['id']
|
|
}
|
|
try:
|
|
data[sale_id]['tasks'][key]['lines'].append(line_)
|
|
except Exception:
|
|
p['device'] = p['host']
|
|
p['profile'] = ''
|
|
data[sale_id]['tasks'][key] = {
|
|
'printer': p,
|
|
'sale': sale_number,
|
|
'work_station': p['name'],
|
|
'lines': [line_]
|
|
}
|
|
|
|
for sale_id, value in data.items():
|
|
args = {
|
|
'sale_id': sale_id,
|
|
'repeat': False,
|
|
}
|
|
orders, _ = cls.get_order2print(args)
|
|
value['orders'] = orders
|
|
|
|
return list(data.values())
|
|
|
|
def get_data_for_stations(self):
|
|
# function deprecated
|
|
data_grouped_printer = {}
|
|
if not self.number:
|
|
self.set_number([self])
|
|
data_sale = self.number
|
|
shop = self.shop
|
|
line_commanded = []
|
|
for line in self.lines:
|
|
if not line.task_printed:
|
|
line_commanded.append(line)
|
|
qty = line.quantity
|
|
note = line.note
|
|
line_id = line.id
|
|
tasks = line.product.tasks
|
|
att_getter = attrgetter("name")
|
|
att_getter_p = attrgetter("host", "interface", "port", "row_characters")
|
|
for t in tasks:
|
|
station = t.work_station
|
|
station_id = station.id
|
|
name = att_getter(t)
|
|
value = {
|
|
'name': name, 'qty': qty, 'note': note,
|
|
'id': line_id, 'task_id': t.id}
|
|
for p in t.work_station.printers:
|
|
key = str(p.id) + '_' + str(station_id)
|
|
if p.shop == shop:
|
|
try:
|
|
data_grouped_printer[key]['lines'].append(value)
|
|
except Exception:
|
|
host, interface, port, row_characters = att_getter_p(p)
|
|
value_printer = {
|
|
'device': host,
|
|
'interface': interface,
|
|
'profile': '',
|
|
'row_characters': row_characters
|
|
}
|
|
data_grouped_printer[key] = {}
|
|
data_grouped_printer[key]['printer'] = value_printer
|
|
data_grouped_printer[key]['sale'] = data_sale
|
|
data_grouped_printer[key]['work_station'] = station.name
|
|
data_grouped_printer[key]['lines'] = [value]
|
|
# Line.write(line_commanded, {'status_order': 'commanded'})
|
|
return data_grouped_printer
|
|
|
|
@classmethod
|
|
def delete(cls, sales):
|
|
has_order_sended = any(line.order_sended for sale in sales for line in sale.lines)
|
|
if has_order_sended:
|
|
raise DeleteSaleError(
|
|
gettext('sale_pos_frontend_rest.msg_sale_delete_error'))
|
|
super(Sale, cls).delete(sales)
|
|
|
|
@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:
|
|
raise PayValidationError(
|
|
gettext('sale_pos_frontend_rest.msg_message_error', s='A draft statement payments has not been created.'))
|
|
|
|
if not sale.number:
|
|
cls.set_number([sale])
|
|
|
|
if not sale.party.account_receivable:
|
|
raise PayValidationError(
|
|
gettext('sale_pos_frontend_rest.msg_party_not_account_receivable', s=sale.party.name))
|
|
|
|
account = sale.party.account_receivable.id
|
|
|
|
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:
|
|
# fields = args['fields']
|
|
print('args....', args)
|
|
consumer, = Consumer.create([args])
|
|
# if consumer and consumer.party:
|
|
# party = consumer.party
|
|
# party.write([party], {'notes': notes})
|
|
# return cls._get_object(consumer)
|
|
|
|
return {
|
|
'id': consumer.id,
|
|
'name': consumer.name,
|
|
'phone': consumer.phone,
|
|
'address': consumer.address or '',
|
|
'notes': consumer.notes,
|
|
'delivery': consumer.delivery
|
|
}
|
|
|
|
@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 _move(cls, from_location, to_location, company, product, uom,
|
|
quantity):
|
|
Move = Pool().get('stock.move')
|
|
move = Move(
|
|
product=product,
|
|
uom=uom,
|
|
quantity=quantity,
|
|
from_location=from_location,
|
|
to_location=to_location,
|
|
company=company,
|
|
currency=company.currency if company else None,
|
|
state='draft',
|
|
)
|
|
return move
|
|
|
|
@classmethod
|
|
def _explode_move_values(cls, from_location, to_location, company,
|
|
bom_io, quantity):
|
|
move = cls._move(from_location, to_location, company,
|
|
bom_io.product, bom_io.uom, quantity)
|
|
move.from_location = from_location.id if from_location else None
|
|
move.to_location = to_location.id if to_location else None
|
|
move.unit_price_required = move.on_change_with_unit_price_required()
|
|
return move
|
|
|
|
@classmethod
|
|
def _create_productions(cls, lines):
|
|
pool = Pool()
|
|
Move = Pool().get('stock.move')
|
|
Location = pool.get('stock.location')
|
|
Bom = pool.get('production.bom')
|
|
Uom = pool.get('product.uom')
|
|
for line in lines:
|
|
if hasattr(line, 'production') and line.production:
|
|
return
|
|
if line.product.producible:
|
|
boms = Bom.search([
|
|
('output_products', '=', line.product.id)
|
|
])
|
|
|
|
if not boms:
|
|
continue
|
|
raise ProductionValidationWarning(
|
|
gettext('sale_pos_frontend_rest.msg_msg_product_without_bom', product=line.product.rec_name))
|
|
|
|
else:
|
|
bom_ = boms[0]
|
|
locations = Location.search([
|
|
('type', '=', 'production'),
|
|
])
|
|
location_ = locations[0] if locations else None
|
|
if not hasattr(line, 'sale'):
|
|
return
|
|
sale = line.sale
|
|
date_ = sale.sale_date
|
|
product_ = line.product
|
|
|
|
if not (bom_ and product_ and product_.default_uom):
|
|
return
|
|
|
|
if sale.warehouse:
|
|
storage_location = sale.warehouse.storage_location
|
|
else:
|
|
storage_location = None
|
|
factor = bom_.compute_factor(product_, line.quantity or 0,
|
|
product_.default_uom)
|
|
|
|
inputs = []
|
|
for input_ in bom_.inputs:
|
|
quantity = input_.compute_quantity(factor)
|
|
move = cls._explode_move_values(storage_location,
|
|
location_, sale.company, input_, quantity)
|
|
if move:
|
|
move.planned_date = date_
|
|
move.effective_date = date_
|
|
move.save()
|
|
inputs.append(move)
|
|
quantity = Uom.compute_qty(input_.uom, line.quantity,
|
|
input_.product.default_uom, round=False)
|
|
|
|
outputs = []
|
|
for output in bom_.outputs:
|
|
quantity = output.compute_quantity(factor)
|
|
move = cls._explode_move_values(location_, storage_location,
|
|
sale.company, output, quantity)
|
|
if move:
|
|
move.planned_date = date_
|
|
move.effective_date = date_
|
|
move.unit_price = Decimal(0)
|
|
move.save()
|
|
outputs.append(move)
|
|
|
|
moves = inputs + outputs
|
|
Move.do(inputs + outputs)
|
|
sale.production_moves = moves
|
|
sale.save()
|
|
|
|
def get_productions(self, name):
|
|
productions = []
|
|
for line in self.lines:
|
|
if hasattr(line, 'production') and 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']
|
|
stock_move_table = Table('stock_move')
|
|
cursor = Transaction().connection.cursor()
|
|
if not ids:
|
|
return 'end'
|
|
for sale in Sale.browse(ids):
|
|
stock_moves = [line.id for line in sale.production_moves]
|
|
if stock_moves:
|
|
cursor.execute(*stock_move_table.update(
|
|
columns=[stock_move_table.state],
|
|
values=['draft'],
|
|
where=stock_move_table.id.in_(stock_moves)
|
|
))
|
|
|
|
cursor.execute(*stock_move_table.delete(
|
|
where=stock_move_table.id.in_(stock_moves))
|
|
)
|
|
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 OrderStatusTime(ModelSQL, ModelView):
|
|
"Sale Order Status Time"
|
|
__name__ = 'sale.order_status.time'
|
|
_rec_name = 'sale'
|
|
|
|
sale = fields.Many2One('sale.sale', 'Sale', ondelete='CASCADE')
|
|
requested = fields.DateTime('Requested')
|
|
commanded = fields.DateTime('commanded')
|
|
dispatched = fields.DateTime('Dispatched')
|
|
delivered = fields.DateTime('Delivered')
|
|
rejected = fields.DateTime('Rejected')
|
|
cancelled = fields.DateTime('Cancelled')
|
|
|
|
|
|
class SaleLine(metaclass=PoolMeta):
|
|
__name__ = 'sale.line'
|
|
production = fields.Many2One('production', 'Production')
|
|
status_order = fields.Selection(OPTIONS_STATUS, 'Status Order')
|
|
without_task = fields.Boolean('Without Task')
|
|
tasks = fields.One2Many('production.task', 'line', 'Tasks')
|
|
|
|
@staticmethod
|
|
def default_status_order():
|
|
return 'draft'
|
|
|
|
@classmethod
|
|
def mark_tasks_printed(cls, args):
|
|
Task = Pool().get('production.task')
|
|
task_ids = args.get('task_ids')
|
|
tasks = Task.browse(task_ids)
|
|
Task.write(list(tasks), {'state': 'commanded'})
|
|
|
|
@classmethod
|
|
def get_data_command_and_task(cls, args):
|
|
orders = cls.get_data_command(args)
|
|
tasks = cls.get_data_tasks(args)
|
|
return {'orders': orders, 'tasks': tasks}
|
|
|
|
@classmethod
|
|
def get_data_command(cls, args):
|
|
Sale = Pool().get('sale.sale')
|
|
Printer = Pool().get('sale.pos_printer')
|
|
|
|
one_hour_ago = str(datetime.now() - timedelta(hours=1))
|
|
shop = args.get('shop')
|
|
|
|
fields_printer = [
|
|
'shop', 'name',
|
|
'host', 'interface',
|
|
'port', 'row_characters',
|
|
]
|
|
printers = Printer.search_read(['shop', '=', shop],
|
|
fields_names=fields_printer)
|
|
printers = {p['id']: p for p in printers}
|
|
dom = [
|
|
("sale.shop", "=", shop),
|
|
("sale.state", "in", ("draft", "quotation")),
|
|
("status_order", "=", 'requested'),
|
|
("create_date", ">=", one_hour_ago),
|
|
]
|
|
if args.get('sale_id'):
|
|
dom.append(('sale', '=', args['sale_id']))
|
|
fields = [
|
|
'sale', 'product.name',
|
|
'product.template.printers',
|
|
'product.template.categories',
|
|
'quantity', 'note'
|
|
]
|
|
lines = cls.search_read(dom, fields_names=fields)
|
|
|
|
sale_ids = set(ln['sale'] for ln in lines)
|
|
fields_sales = [
|
|
'consumer.name', 'consumer.phone',
|
|
'consumer.address', 'consumer.notes',
|
|
'party.name', 'turn', 'number', 'invoice_number',
|
|
'position', 'salesman.rec_name', 'comment',
|
|
'delivery_charge', 'payment_term.name', 'delivery_amount',
|
|
'total_amount', 'shop.name', 'kind', 'table_assigned.name'
|
|
]
|
|
sales = Sale.search_read(['id', 'in', sale_ids], fields_names=fields_sales)
|
|
sales = {
|
|
s['id']: {
|
|
'id': s['id'],
|
|
'consumer': s['consumer.'],
|
|
'turn': s['turn'],
|
|
'number': s['invoice_number'],
|
|
'sale_number': s['number'],
|
|
'position': s.get('position', ''),
|
|
'party': s.get('party.', {}).get('name'),
|
|
'kind': s['kind'],
|
|
'delivery_amount': s['delivery_amount'],
|
|
'salesman': s.get('salesman.', {}).get('rec_name'),
|
|
'comment': s.get('comment', ''),
|
|
'payment_term': s.get('payment_term.', {}).get('name', ''),
|
|
'delivery_charge': s['delivery_charge'],
|
|
'total_amount': str(s['total_amount']),
|
|
'shop': s.get('shop.', {}).get('name', ''),
|
|
'table_assigned': s.get('table_assigned.', {}).get('name', ''),
|
|
}
|
|
for s in sales
|
|
}
|
|
orders = {}
|
|
lines_mark_sended = []
|
|
for line in lines:
|
|
sale_id = line['sale']
|
|
sale = sales[sale_id]
|
|
printers_ = line['product.']['template.'].get('printers', [])
|
|
|
|
if not printers_:
|
|
lines_mark_sended.append(line['id'])
|
|
continue
|
|
|
|
value_line = {
|
|
'name': line['product.']['name'],
|
|
'quantity': str(line['quantity']),
|
|
'unit_price': int(0), # validate is this field is neccesary
|
|
'note': line['note'],
|
|
'id': line['id']
|
|
}
|
|
categories = line['product.']['template.'].get('categories')
|
|
for printer_id in printers_:
|
|
printer = printers.get(printer_id)
|
|
if not printer:
|
|
continue
|
|
|
|
key = f'{sale_id}_{printer_id}'
|
|
|
|
if key not in orders:
|
|
orders[key] = {**printer, **sale, 'lines': []}
|
|
|
|
if 'categories.' in printer:
|
|
orders[key]['lines'] = {
|
|
c['sequence']: {
|
|
'name': c.get('category.', {}).get('name'),
|
|
'lines': []} for c in printer['categories']}
|
|
orders[key]['categories'] = {c['category.']['id']: c['sequence'] for c in printer['categories.']}
|
|
|
|
if isinstance(orders[key]['lines'], list):
|
|
orders[key]['lines'].append(value_line)
|
|
else:
|
|
key_id = orders[key]['categories'].get(categories[0], 'others')
|
|
|
|
if 'others' not in orders[key]['lines']:
|
|
orders[key]['lines']['others'] = {'name': 'OTROS', 'lines': []}
|
|
|
|
orders[key]['lines'][key_id]['lines'].append(value_line)
|
|
return list(orders.values())
|
|
|
|
@classmethod
|
|
def get_data_tasks(cls, args):
|
|
Task = Pool().get('production.task')
|
|
one_hour_ago = str(datetime.now() - timedelta(hours=1))
|
|
shop = args['shop']
|
|
fields = [
|
|
'sale.number', 'quantity', 'note',
|
|
'product.tasks.printers.shop',
|
|
'product.tasks.printers.name',
|
|
'product.tasks.printers.host',
|
|
'product.tasks.printers.interface',
|
|
'product.tasks.printers.port',
|
|
'product.tasks.printers.row_characters',
|
|
'product.tasks.name']
|
|
dom = [
|
|
("sale.shop", "=", shop),
|
|
("sale.state", "in", ("draft", "quotation")),
|
|
("create_date", ">=", one_hour_ago),
|
|
("without_task", "!=", True),
|
|
("tasks", '=', None)
|
|
]
|
|
if args.get('sale_id'):
|
|
dom.append(('sale', '=', args['sale']))
|
|
lines = cls.search_read(
|
|
dom, fields_names=fields,
|
|
order=[('sale', 'ASC'), ('id', 'DESC')])
|
|
|
|
to_create = []
|
|
lines_without_tasks = []
|
|
print(lines, 'validate tasks')
|
|
for line in lines:
|
|
quantity = line['quantity']
|
|
note = line['note']
|
|
line_id = line['id']
|
|
sale_number = line['sale.']['number']
|
|
tasks = line['product.']['tasks.']
|
|
if not tasks:
|
|
lines_without_tasks.append(line_id)
|
|
|
|
for t in line['product.']['tasks.']:
|
|
task_id = t['id']
|
|
for p in t['printers.']:
|
|
if p['shop'] == shop:
|
|
value = {
|
|
'quantity': quantity,
|
|
'note': note,
|
|
'line': line_id,
|
|
'name': t['name'],
|
|
'sale_number': sale_number,
|
|
'task': task_id,
|
|
'state': 'pending',
|
|
'printer': p['id']}
|
|
to_create.append(value)
|
|
if lines_without_tasks:
|
|
lines_ = cls.browse(lines_without_tasks)
|
|
cls.write(list(lines_), {'without_task': True})
|
|
Task.create(to_create)
|
|
data = Task.get_tasks_to_print(args)
|
|
return data
|
|
|
|
@classmethod
|
|
def delete(cls, lines):
|
|
HistoryDelete = Pool().get('sale.line._history.delete')
|
|
lines_to_create = []
|
|
lines_to_create_append = lines_to_create.append
|
|
for line in lines:
|
|
if line.order_sended:
|
|
value = {
|
|
'line_id': line.id,
|
|
'product': line.product,
|
|
'quantity': line.quantity,
|
|
'date': line.sale.sale_date,
|
|
'order_status': line.sale.order_status,
|
|
'sale': line.sale.id,
|
|
'sale_state': line.sale.state,
|
|
'unit_price': line.unit_price,
|
|
'base_price': line.base_price,
|
|
'note': line.note,
|
|
'shop': line.sale.shop,
|
|
'salesman': line.sale.salesman,
|
|
'line_created': line.create_date
|
|
}
|
|
lines_to_create_append(value)
|
|
super(SaleLine, cls).delete(lines)
|
|
if lines_to_create:
|
|
HistoryDelete.create(lines_to_create)
|
|
|
|
|
|
class SaleLineHistoryDelete(ModelView, ModelSQL):
|
|
'Sale Line History Delete'
|
|
__name__ = 'sale.line._history.delete'
|
|
|
|
product = fields.Many2One('product.product', 'Product')
|
|
line_id = fields.Char('Line id')
|
|
order_status = fields.Char('Order Status')
|
|
sale = fields.Many2One('sale.sale', 'Sale')
|
|
sale_state = fields.Char('Sale State')
|
|
quantity = fields.Float('Quantity',
|
|
digits=(16, Eval('unit_digits', 2)))
|
|
shop = fields.Many2One('sale.shop', 'Shop')
|
|
unit_price = fields.Numeric('Unit Price', digits=price_digits)
|
|
date = fields.Date('Date')
|
|
base_price = fields.Numeric('Base Price', digits=price_digits)
|
|
note = fields.Text('Note')
|
|
salesman = fields.Many2One('company.employee', 'Salesman')
|
|
line_created = fields.DateTime('Line Created')
|
|
|
|
|
|
class SaleLineHistoryDeleteStart(ModelSQL, ModelView):
|
|
'Sale Line History Delete Start'
|
|
__name__ = 'line_history.delete_start'
|
|
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
start_date = fields.Date('Date', required=True)
|
|
end_date = fields.Date('Date', required=True)
|
|
shop = fields.Many2One('sale.shop', 'Shop', required=True)
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@staticmethod
|
|
def default_shop():
|
|
return Transaction().context.get('shop')
|
|
|
|
@staticmethod
|
|
def default_end_date():
|
|
Date = Pool().get('ir.date')
|
|
return Date.today()
|
|
|
|
@staticmethod
|
|
def default_start_date():
|
|
Date = Pool().get('ir.date')
|
|
today = Date.today()
|
|
date_ = date(today.year, today.month, 1)
|
|
return date_
|
|
|
|
|
|
class SaleLineHistoryDeleteWizard(Wizard):
|
|
'Sale Line History Delete'
|
|
__name__ = 'line_history.delete_wizard'
|
|
|
|
start = StateView(
|
|
'line_history.delete_start',
|
|
'sale_pos_frontend_rest.line_history_delete_view_form',
|
|
[
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
print_ = StateReport('line_history.delete_report')
|
|
|
|
def do_print_(self, action):
|
|
report_context = {
|
|
'company': self.start.company.id,
|
|
'start_date': self.start.start_date,
|
|
'end_date': self.start.end_date,
|
|
'shop': self.start.shop.id,
|
|
}
|
|
return action, report_context
|
|
|
|
def transition_print_(self):
|
|
return 'end'
|
|
|
|
|
|
class SaleLineHistoryDeleteReport(Report):
|
|
'Sale Line History Delete Report'
|
|
__name__ = 'line_history.delete_report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
History = pool.get('sale.line._history.delete')
|
|
Company = pool.get('company.company')
|
|
Shop = pool.get('sale.shop')
|
|
domain = [
|
|
('date', '>=', data['start_date']),
|
|
('date', '<=', data['end_date']),
|
|
]
|
|
if data['shop']:
|
|
domain.append(('shop', '=', data['shop']))
|
|
records = History.search_read(domain)
|
|
record_ids = [r['id'] for r in records]
|
|
records = cls._get_records(record_ids, 'sale.line._history.delete', data)
|
|
company = Company(data['company'])
|
|
report_context['company'] = company
|
|
report_context['shop_name'] = Shop.name
|
|
report_context['records'] = records
|
|
return report_context
|
|
|
|
|
|
class SaleSquareBoxGlobal(SaleSquareBox):
|
|
'Sale Square Box Global'
|
|
__name__ = 'sale_pos_frontend_rest.sale_square_box_global'
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(SaleSquareBoxGlobal, cls).__setup__()
|
|
cls.print_ = StateReport('sale_pos_frontend_rest.sale_square_box_global_report')
|
|
|
|
|
|
class SaleSquareBoxGlobalReport(Report):
|
|
'Square Box Global Report'
|
|
__name__ = 'sale_pos_frontend_rest.sale_square_box_global_report'
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(SaleSquareBoxGlobalReport, cls).__setup__()
|
|
|
|
@classmethod
|
|
def get_stament_cash(cls, statement):
|
|
Statement = Pool().get('account.statement')
|
|
if statement:
|
|
value = {
|
|
'statement': Statement(statement['id']),
|
|
'base': statement['total_money'] or 0,
|
|
'bills': sum(k['amount'] for k in statement['count_money.'] if float(k['bill']) >= 1000),
|
|
'coins': sum(k['amount'] for k in statement['count_money.'] if float(k['bill']) < 1000)
|
|
}
|
|
return value
|
|
|
|
@classmethod
|
|
def get_context(cls, records, header, data):
|
|
report_context = super().get_context(records, header, data)
|
|
pool = Pool()
|
|
Invoice = pool.get('account.invoice')
|
|
Company = pool.get('company.company')
|
|
Device = pool.get('sale.device')
|
|
company = Company(data['company'])
|
|
Statement = pool.get('account.statement')
|
|
Shop = pool.get('sale.shop')
|
|
# User = pool.get('res.user')
|
|
|
|
dom_statement = [
|
|
('date', '=', data['date']),
|
|
]
|
|
devices = Device.search([('shop', '=', data['shop'])])
|
|
device_ids = [d.id for d in devices]
|
|
dom_statement.append(('sale_device', 'in', device_ids))
|
|
|
|
if data['turn']:
|
|
dom_statement.append(('turn', '=', int(data['turn'])))
|
|
|
|
fields_statement = ['name', 'create_date', 'journal.kind', 'balance', 'count_money.bill', 'count_money.quantity', 'count_money.amount', 'total_money']
|
|
cash = None
|
|
statements = Statement.search_read(dom_statement, fields_names=fields_statement)
|
|
lst_statements = []
|
|
balance_statements = []
|
|
for st in statements:
|
|
kind = st['journal.']['kind']
|
|
if kind == 'cash':
|
|
cash = st
|
|
else:
|
|
balance_statements.append(st['balance'])
|
|
lst_statements.append(st)
|
|
|
|
dom_invoices = [
|
|
('company', '=', data['company']),
|
|
('invoice_date', '=', data['date']),
|
|
('type', '=', 'out'),
|
|
('shop', '=', data['shop']),
|
|
('turn', '=', int(data['turn']))
|
|
]
|
|
fields_inv = ['number', 'invoice_type', 'total_amount', 'state',
|
|
'payment_term.payment_type', 'sales.residual_amount',
|
|
'payment_term.rec_name', 'party.name', 'reference']
|
|
invoices = Invoice.search_read(dom_invoices, fields_names=fields_inv)
|
|
pos = []
|
|
electronic = []
|
|
cancelled = []
|
|
credits = []
|
|
invs = []
|
|
pos_append = pos.append
|
|
electronic_append = electronic.append
|
|
cancelled_append = cancelled.append
|
|
credits_append = credits.append
|
|
invs_append = invs.append
|
|
for invoice in invoices:
|
|
residual_amount = invoice['sales.'][0]['residual_amount']
|
|
if residual_amount > 0:
|
|
invoice['residual_amount'] = residual_amount
|
|
credits_append(residual_amount)
|
|
invs_append(invoice)
|
|
if invoice['state'] == 'cancelled':
|
|
cancelled_append((invoice['total_amount'], invoice))
|
|
elif invoice['invoice_type'] == '1':
|
|
electronic_append(invoice['total_amount'])
|
|
else:
|
|
pos_append(invoice['total_amount'])
|
|
|
|
report_context['total_sale'] = sum(pos) + sum(electronic)
|
|
report_context['pos'] = sum(pos)
|
|
report_context['electronic'] = sum(electronic)
|
|
report_context['cash'] = cls.get_stament_cash(cash)
|
|
report_context['credits'] = sum(credits)
|
|
report_context['invoice_credits'] = invs
|
|
report_context['statements'] = lst_statements
|
|
report_context['balance_statements'] = balance_statements
|
|
report_context['data'] = data
|
|
report_context['company'] = company
|
|
report_context['shop'] = Shop(data['shop'])
|
|
return report_context
|