diff --git a/__init__.py b/__init__.py
index 3da5661..b7684b6 100644
--- a/__init__.py
+++ b/__init__.py
@@ -27,9 +27,10 @@ def register():
sale.OrderStatusTime,
shop.SaleShop,
bom.BOM,
- production.WorkStation,
- production.WorkStationPrinter,
+ # production.WorkStation,
+ # production.WorkStationPrinter,
production.ConfigurationTask,
+ production.TaskPrinter,
production.Task,
product.ProductMixOption,
product.Product,
diff --git a/bom.py b/bom.py
index d0bcb8d..232527c 100644
--- a/bom.py
+++ b/bom.py
@@ -12,8 +12,6 @@ def round_dec(number):
class BOM(metaclass=PoolMeta):
__name__ = 'production.bom'
- tasks_configuration = fields.One2Many('production.configuration_task', 'ldm', 'Tasks Configuration')
-
@classmethod
def copy(cls, records, default=None):
if default is None:
@@ -21,5 +19,4 @@ class BOM(metaclass=PoolMeta):
else:
default = default.copy()
default.setdefault('output_products', None)
- default.setdefault('tasks_configuration', None)
return super(BOM, cls).copy(records, default=default)
diff --git a/product.py b/product.py
index 2e386f1..919abc7 100644
--- a/product.py
+++ b/product.py
@@ -5,6 +5,7 @@ from trytond.pool import PoolMeta
from .exceptions import ProductMixRequiredError
from trytond.i18n import gettext
+
class Product(metaclass=PoolMeta):
__name__ = 'product.product'
products_mix = fields.Many2Many('product.product-mix.option',
@@ -17,8 +18,8 @@ class Product(metaclass=PoolMeta):
if self.products_mix and self.quantity_mix_required and len(self.products_mix) < self.quantity_mix_required:
raise ProductMixRequiredError(
gettext(
- "sale_pos_frontend_rest.msg_quantity_mix_error",
- product_mix=len(self.products_mix),
+ "sale_pos_frontend_rest.msg_quantity_mix_error",
+ product_mix=len(self.products_mix),
quantity=self.quantity_mix_required))
@classmethod
diff --git a/production.py b/production.py
index 0cedbbd..b8dfc3b 100644
--- a/production.py
+++ b/production.py
@@ -4,10 +4,11 @@
from trytond.model import fields, ModelSQL, ModelView
from trytond.transaction import Transaction
from decimal import Decimal
-from trytond.pool import PoolMeta, Pool
+from datetime import datetime, timedelta
+from trytond.pool import Pool
from trytond.pyson import Eval
-from trytond.exceptions import UserError
-from trytond.i18n import gettext
+# from trytond.exceptions import UserError
+# from trytond.i18n import gettext
def round_dec(number):
@@ -16,21 +17,29 @@ def round_dec(number):
STATES = {'required': True}
+# for remove
+# class WorkStation(ModelSQL, ModelView):
+# "Work Station"
+# __name__ = 'production.workstation'
-class WorkStation(ModelSQL, ModelView):
- "Work Station"
- __name__ = 'production.workstation'
+# name = fields.Char('Name', states=STATES)
+# code = fields.Char('Code', states=STATES)
+# printers = fields.Many2Many('production.workstation.pos_printer', 'work_station', 'printer', 'Printers')
- name = fields.Char('Name', states=STATES)
- code = fields.Char('Code', states=STATES)
- printers = fields.Many2Many('production.workstation.pos_printer', 'work_station', 'printer', 'Printers')
+# for remove
+# class WorkStationPrinter(ModelSQL, ModelView):
+# "Work Station"
+# __name__ = 'production.workstation.pos_printer'
+
+# work_station = fields.Many2One('production.workstation', 'Work Station')
+# printer = fields.Many2One('sale.pos_printer', 'Printer')
-class WorkStationPrinter(ModelSQL, ModelView):
- "Work Station"
- __name__ = 'production.workstation.pos_printer'
+class TaskPrinter(ModelSQL, ModelView):
+ "Task Printer"
+ __name__ = 'production.task.pos_printer'
- work_station = fields.Many2One('production.workstation', 'Work Station')
+ task = fields.Many2One('production.configuration_task', 'Tasks')
printer = fields.Many2One('sale.pos_printer', 'Printer')
@@ -40,24 +49,33 @@ class ConfigurationTask(ModelSQL, ModelView):
name = fields.Char('Name', states=STATES)
description = fields.Text('Description')
- ldm = fields.Many2One('production.bom', 'LDM', states=STATES)
product = fields.Many2One('product.product', 'Product',
search_context={
'outputs': Eval('_parent_ldm', {}).get('outputs')})
- work_station = fields.Many2One('production.workstation', 'Work Station', states=STATES)
+ printers = fields.Many2Many('production.task.pos_printer', 'task',
+ 'printer', 'Printers', states=STATES)
+ # for remove
+ # ldm = fields.Many2One('production.bom', 'LDM', states=STATES)
+ # work_station = fields.Many2One('production.workstation', 'Work Station', states=STATES)
@classmethod
- def create(cls, vlist):
- pool = Pool()
- LDM = pool.get('production.bom')
- vlist = [x.copy() for x in vlist]
- for vals in vlist:
- if 'ldm' in vals:
- ldm = LDM(vals['ldm'])
- if not ldm.outputs:
- raise UserError(gettext('sale_pos_frontend_rest.msg_missing_product_output'))
- vals['product'] = ldm.outputs[0].product.id
- return super(ConfigurationTask, cls).create(vlist)
+ def __register__(cls, module_name):
+ super(ConfigurationTask, cls).__register__(module_name)
+
+ table = cls.__table_handler__(module_name)
+ if table.column_exist('ldm'):
+ TaskPrinter = Pool().get('production.task.pos_printer')
+ query = '''select t.id, p.printer from
+ production_configuration_task as t
+ join production_workstation_pos_printer as p
+ on p.work_station=t.work_station'''
+ cursor = Transaction().connection.cursor()
+ cursor.execute(query)
+ res = cursor.fetchall()
+ to_create = [{'task': t, 'printer': p} for t, p in res]
+ TaskPrinter.create(to_create)
+ table.drop_column('ldm')
+ table.drop_column('work_station')
class Task(ModelSQL, ModelView):
@@ -65,17 +83,63 @@ class Task(ModelSQL, ModelView):
__name__ = 'production.task'
name = fields.Char('Name', states=STATES)
- description = fields.Text('Description')
- ldm = fields.Many2One('production.bom', 'LDM', states=STATES)
- work_station = fields.Many2One('production.workstation', 'Work Station', states=STATES)
- planned_date = fields.Date('Planned Date')
+ note = fields.Text('Note')
+ line = fields.Many2One('sale.line', 'Sale Line', states={'readonly': True})
quantity = fields.Integer('Quantity')
- state = fields.Selection([('pending', 'Pending'), ('done', 'Done')], 'State')
+ state = fields.Selection([
+ ('pending', 'Pending'),
+ ('commanded', 'Commanded'),
+ ('done', 'Done')], 'State')
+ printer = fields.Many2One('sale.pos_printer', 'Printer')
+ task = fields.Many2One('production.configuration_task', 'Task')
+ sale_number = fields.Char('Sale Number')
+ # ldm = fields.Many2One('production.bom', 'LDM', states=STATES)
@classmethod
def __setup__(cls):
super(Task, cls).__setup__()
+ @classmethod
+ def get_tasks_to_print(cls, args):
+ one_hour_ago = str(datetime.now() - timedelta(hours=1))
+ dom = [
+ ('state', '=', 'pending'),
+ ('create_date', '>=', one_hour_ago)
+ ]
+ if args.get('sale_id'):
+ dom.append('line.sale', '=', args['sale_id'])
+
+ fields = [
+ 'name', 'note', 'quantity', 'sale_number',
+ 'line', 'line.sale',
+ 'printer.name', 'printer.shop', 'printer.host',
+ 'printer.interface', 'printer.port', 'printer.row_characters',
+ ]
+ tasks = cls.search_read(dom, fields_names=fields, order=[('id', 'DESC')])
+ tasks_print = {}
+ for t in tasks:
+ printer_id = t['printer.']['id']
+ sale_id = t['line.']['sale']
+ key = str(printer_id) + '_' + str(sale_id)
+ line = {
+ 'quantity': t['quantity'],
+ 'name': t['name'],
+ 'line': t['line.']['id'],
+ 'task': t['id'],
+ 'note': t['note']
+ }
+ try:
+ tasks_print[key]['lines'].append(line)
+ except Exception:
+ tasks_print[key] = {}
+ tasks_print[key]['lines'] = [line]
+ value_printer = t['printer.']
+ value_printer['device'] = value_printer['host']
+ value_printer['profile'] = ''
+ tasks_print[key]['printer'] = t['printer.']
+ tasks_print[key]['sale'] = t['sale_number']
+ tasks_print[key]['work_station'] = value_printer['name']
+ return list(tasks_print.values())
# class Production(metaclass=PoolMeta):
# __name__ = 'production'
diff --git a/sale.py b/sale.py
index 2d1f61c..a45bf90 100644
--- a/sale.py
+++ b/sale.py
@@ -88,16 +88,24 @@ class Sale(metaclass=PoolMeta):
"""
Status = Pool().get('sale.order_status.time')
Line = Pool().get('sale.line')
- sale = cls(args['sale_id'])
- to_write = {'order_status': 'commanded'}
- now = datetime.now()
- order_time = sale.order_status_time
- if order_time:
- Status.write([order_time], {'commanded': now})
+ lines_ = args.get('lines_ids', [])
+
+ if args.get('sale_id'):
+ sale = cls(args['sale_id'])
+ sales = [sale]
else:
- status, = Status.create([{'commanded': now, 'requested': now, 'sale': args['sale_id']}])
- to_write['order_status_time'] = status
- cls.write([sale], to_write)
+ 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)
@@ -113,22 +121,20 @@ class Sale(metaclass=PoolMeta):
@classmethod
def get_orders_to_command(cls, args):
-
+ # function deprecated for remove
pool = Pool()
Line = pool.get('sale.line')
- WorkStation = pool.get('production.workstation')
shop = args['shop']
- stations = WorkStation.search_read([],
- fields_names=[
- "name", "printers.shop",
- "printers.host", "printers.interface",
- "printers.port", "printers.row_characters"])
- stations = {s['id']: s for s in stations}
_date = str(datetime.now() - timedelta(hours=1))
fields = [
'sale.number', 'quantity', 'note',
- 'product.tasks.work_station',
+ '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),
@@ -149,6 +155,7 @@ class Sale(metaclass=PoolMeta):
sale_number = line['sale.']['number']
qty = line['quantity']
note = line['note']
+ id_ = str(line['id'])
try:
data[sale_id]
@@ -160,13 +167,17 @@ class Sale(metaclass=PoolMeta):
}
for t in line['product.']['tasks.']:
- line_ = {'qty': qty, 'note': note, 'name': t['name']}
- station_id = t['work_station']
- station = stations[station_id]
- for p in station['printers.']:
- key = str(p['id']) + '_' + str(station_id)
+ 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:
@@ -175,7 +186,7 @@ class Sale(metaclass=PoolMeta):
data[sale_id]['tasks'][key] = {
'printer': p,
'sale': sale_number,
- 'work_station': station['name'],
+ 'work_station': p['name'],
'lines': [line_]
}
@@ -190,10 +201,7 @@ class Sale(metaclass=PoolMeta):
return list(data.values())
def get_data_for_stations(self):
- # TaskConfig = Pool().get('production.configuration_task')
- # Line = Pool().get('sale.line')
- # print('ingesa nnn', self.id)
- # print(line.status_order, 'status order')
+ # function deprecated
data_grouped_printer = {}
if not self.number:
self.set_number([self])
@@ -201,10 +209,11 @@ class Sale(metaclass=PoolMeta):
shop = self.shop
line_commanded = []
for line in self.lines:
- if line.status_order in ('draft', 'requested'):
+ 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")
@@ -212,7 +221,9 @@ class Sale(metaclass=PoolMeta):
station = t.work_station
station_id = station.id
name = att_getter(t)
- value = {'name': name, 'qty': qty, 'note': note}
+ 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:
@@ -488,11 +499,196 @@ 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')
diff --git a/tryton.cfg b/tryton.cfg
index 80846ae..8ea37bf 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
[tryton]
-version=6.0.6
+version=6.0.7
depends:
sale
production_accounting
diff --git a/view/bom_form.xml b/view/bom_form.xml
index 5a1eb3a..d49b669 100644
--- a/view/bom_form.xml
+++ b/view/bom_form.xml
@@ -3,9 +3,9 @@
this repository contains the full copyright notices and license terms. -->