366 lines
16 KiB
Python
366 lines
16 KiB
Python
from QT import QtWidgets, QtGui, QT
|
|
from _With_Table_Widget_ import _With_Table_Widget_
|
|
from App_State import App_State
|
|
from Action_List import Action_Dialog
|
|
import schema
|
|
import subprocess
|
|
import threading
|
|
import time
|
|
import pathlib
|
|
|
|
class Order_List (_With_Table_Widget_) :
|
|
|
|
settings_group = "order-list"
|
|
Header = "Aufträge"
|
|
Columns = \
|
|
("Warenkorb", "Status", "Bearbeiter", "Kommission", "Kunde", "Linie")
|
|
|
|
State_Map = \
|
|
{ 0 : "neu"
|
|
, 10 : "in Bearbeitung"
|
|
, 20 : "im CAD geöffnet"
|
|
, 25 : "CNC Erzeugung läuft"
|
|
, 90 : "Odoo"
|
|
, 95 : "Zurückgesetzt"
|
|
, 99 : "Storno"
|
|
}
|
|
def __init__ (self, parent = None) :
|
|
super ().__init__ (parent)
|
|
self._view.setContextMenuPolicy (QT.CustomContextMenu)
|
|
self._view.customContextMenuRequested.connect (self._show_context_menu)
|
|
ACT = QtGui.QAction
|
|
self._open_cad = ACT (self.tr ("Im CAD öffnen"))
|
|
self._recreate_cnc = ACT (self.tr ("CNC Programm neu erzeugen"))
|
|
self._reset_order = ACT (self.tr ("Auftrag zurücksetzen"))
|
|
self._cancel = ACT (self.tr ("Auftrag stronieren"))
|
|
self._send_to_odoo = ACT (self.tr ("Auftrag ans Odoo schicken"))
|
|
self._actions = ACT (self.tr ("Aktionsliste"))
|
|
self._reset_state = ACT (self.tr ("Status zurücksetzen"))
|
|
self._open_cad.triggered.connect (self._open_order_in_cad)
|
|
self._recreate_cnc.triggered.connect (self._start_recreate_cnc)
|
|
self._reset_order.triggered.connect (self._reset_order_in_webshop)
|
|
self._cancel.triggered.connect (self._cancel_order)
|
|
self._send_to_odoo.triggered.connect (self._send_oder_to_odoo)
|
|
self._actions.triggered.connect (self._show_actions)
|
|
self._reset_state.triggered.connect (self._reset_order_state)
|
|
self._cad_processes = {}
|
|
# end def __init__
|
|
|
|
def _show_context_menu (self, pos) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
with schema.orm.db_session () :
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
if order.user and order.user.id != App_State.user_id :
|
|
r = QtWidgets.QMessageBox.question \
|
|
( self, self.tr ("Fehler")
|
|
, self.tr
|
|
( "Dieser Auftrag wird bereits von jemand anderes "
|
|
"bearbeitet.\n"
|
|
"Wollen Sie den Auftrag als Bearbeiter übernehmen?"
|
|
)
|
|
)
|
|
if r == QtWidgets.QMessageBox.No :
|
|
return
|
|
App_State.Create_Action \
|
|
( 10
|
|
, f"User changed from {order.user.id} to {App_State.user_id}"
|
|
, order
|
|
)
|
|
order.user = schema.User [App_State.user_id]
|
|
self.update_order (order, False, row_data [0].row ())
|
|
state = order.state
|
|
cm = QtWidgets.QMenu ()
|
|
if state < 20 :
|
|
cm.addAction (self._open_cad)
|
|
cm.addAction (self._recreate_cnc)
|
|
cm.addSeparator ()
|
|
cm.addAction (self._send_to_odoo)
|
|
cm.addSeparator ()
|
|
cm.addAction (self._reset_order)
|
|
cm.addAction (self._cancel)
|
|
cm.addSeparator ()
|
|
cm.addAction (self._actions)
|
|
cm.addSeparator ()
|
|
cm.addAction (self._reset_state)
|
|
cm.exec (self._view.mapToGlobal (pos))
|
|
# end def _show_context_menu
|
|
|
|
def update_order (self, order, new, row = None) :
|
|
if order.active :
|
|
state = self.State_Map [order.state]
|
|
if new :
|
|
row = self._view.rowCount ()
|
|
self._view.setRowCount (row + 1)
|
|
self._add_read_only_string (row, 0, str (order.basket_no))
|
|
self._add_read_only_string (row, 1, state)
|
|
if order.user :
|
|
self._add_read_only_string (row, 2, order.user.username)
|
|
self._add_read_only_string (row, 3, order.commission)
|
|
self._add_read_only_string (row, 4, order.imos_user)
|
|
self._add_read_only_string (row, 5, str (order.production_line))
|
|
else :
|
|
if row is None :
|
|
for row in range (self._view.rowCount ()) :
|
|
if self._view.item (row, 0).text () == order.basket_no :
|
|
break
|
|
else :
|
|
App_State.L.error \
|
|
("Could not find row for order %s", order.basket_no)
|
|
return
|
|
self._update_read_only_string (row, 1, state)
|
|
self._update_read_only_string (row, 2, order.user.username)
|
|
else :
|
|
for row in range (self._view.rowCount ()) :
|
|
if self._view.item (row, 0).text () == order.basket_no :
|
|
self._view.removeRow (row)
|
|
return order.basket_no
|
|
# end def update_order
|
|
|
|
def remove_orders (self, orders) :
|
|
for bno in orders :
|
|
for row in range (self._view.rowCount ()) :
|
|
if self._view.item (row, 0).text () == bno :
|
|
self._view.removeRow (row)
|
|
break
|
|
# end def remove_orders
|
|
|
|
def _open_order_in_cad (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
with schema.orm.db_session () :
|
|
state = schema.State.get ()
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
if order.state < 20 :
|
|
order.state = 20
|
|
self.update_order (order, False, row_data [0].row ())
|
|
order_dwg = r"%s\ImOrder\%s\%s.dwg" \
|
|
% (state.imos_factory_root, bno, bno)
|
|
self._cad_processes [bno] = p = subprocess.Popen \
|
|
( ( order_dwg, ), shell = True )
|
|
threading.Thread \
|
|
( target = self._wait_for_cad_close
|
|
, args = (bno, )
|
|
, daemon = True
|
|
).start ()
|
|
App_State.Create_Action \
|
|
( 20
|
|
, f"IMOS CAD started {order.basket_no}"
|
|
, order
|
|
)
|
|
# end def _open_order_in_cad
|
|
|
|
def _wait_for_cad_close (self, basket_no) :
|
|
App_State.L.info ("Auftrag %s im CAD geöffnet", basket_no)
|
|
p = self._cad_processes [basket_no]
|
|
while p.poll () is None :
|
|
time.sleep (.5)
|
|
del self._cad_processes [basket_no]
|
|
with schema.orm.db_session () :
|
|
order = schema.Order.get (basket_no = basket_no, active = True)
|
|
order.state = 10
|
|
self.update_order (order, False)
|
|
App_State.Create_Action \
|
|
( 25
|
|
, f"IMOS CAD closed {order.basket_no}: Error code {p.poll ()}"
|
|
, order
|
|
)
|
|
App_State.L.info ("CAD für Auftrag %s beendet", basket_no)
|
|
# end def _wait_for_cad_close
|
|
|
|
def _start_recreate_cnc (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
xml = f"""<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
|
<XML Type="JOBPROCESS">
|
|
<BatchJobs>
|
|
<BatchJob>
|
|
<OrderNo>{bno}</OrderNo>
|
|
<BatchName>STANDARD</BatchName>
|
|
<Source>IMOSADMIN</Source>
|
|
</BatchJob>
|
|
</BatchJobs>
|
|
</XML>
|
|
"""
|
|
with schema.orm.db_session () :
|
|
state = schema.State.get ()
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
job_file_name = ( pathlib.Path (state.imos_sim_root)
|
|
/ App_State.sim_batches
|
|
/ f"{bno}.xml"
|
|
)
|
|
txt_file = ( pathlib.Path (state.imos_factory_root)
|
|
/ App_State.imos_done_dir
|
|
/ f"{bno}.txt"
|
|
)
|
|
order.state = 25
|
|
with job_file_name.open ("w") as f :
|
|
f.write (xml)
|
|
if txt_file.exists () :
|
|
txt_file.unlink ()
|
|
self.update_order (order, False, row_data [0].row ())
|
|
threading.Thread \
|
|
( target = self._wait_for_cnc_done
|
|
, args = (bno, )
|
|
, daemon = True
|
|
).start ()
|
|
App_State.Create_Action \
|
|
( 30, f"Start CNC generation for {bno}", order)
|
|
# end def _start_recreate_cnc
|
|
|
|
def _wait_for_cnc_done (self, basket_no) :
|
|
with schema.orm.db_session () :
|
|
state = schema.State.get ()
|
|
txt_file = ( pathlib.Path (state.imos_factory_root)
|
|
/ App_State.imos_done_dir
|
|
/ f"{basket_no}.txt"
|
|
)
|
|
err_file_name = ( pathlib.Path (state.imos_sim_root)
|
|
/ App_State.sim_batches
|
|
/ "Error"
|
|
/ f"{basket_no}.xml"
|
|
)
|
|
while not txt_file.exists () and not err_file_name.exists ():
|
|
time.sleep (0.5)
|
|
App_State.L.debug (f"wait for {txt_file}/{err_file_name}")
|
|
if err_file_name.exists () :
|
|
text = f"Fehler bei der CNC Erzeugung for {basket_no}"
|
|
else :
|
|
text = f"CNC Erzeugung für {basket_no} abgeschlossen"
|
|
with schema.orm.db_session () :
|
|
order = schema.Order.get (basket_no = basket_no, active = True)
|
|
order.state = 10
|
|
self.update_order (order, False)
|
|
App_State.Create_Action (35, text, order)
|
|
# end def _wait_for_cnc_done
|
|
|
|
def _reset_order_in_webshop (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
App_State.L.error ("Reset order in webshop %s", bno)
|
|
# end def _reset_order_in_webshop
|
|
|
|
def _cancel_order (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
App_State.L.error ("Cancel Order %s", bno)
|
|
# end def _cancel_order
|
|
|
|
def _send_oder_to_odoo (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
with schema.orm.db_session () :
|
|
state = schema.State.get ()
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
factory = pathlib.Path (state.imos_factory_root)
|
|
for ext in ".xml", ".txt" :
|
|
sf = factory / App_State.imos_done_dir / f"{bno}{ext}"
|
|
df = factory / App_State.pgiq_dir / f"{bno}{ext}"
|
|
sf.rename (df)
|
|
App_State.L.info ("Auftrag %s für Odoo freigegeben", bno)
|
|
App_State.Create_Action \
|
|
(40, f"Auftrag {bno} für Odoo freigegeben", order)
|
|
order.active = False
|
|
self.update_order (order, False)
|
|
# end def _send_oder_to_odoo
|
|
|
|
def _show_actions (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
with schema.orm.db_session () :
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
Action_Dialog \
|
|
(order.actions.order_by (schema.orm.desc (schema.Action.date))).exec ()
|
|
# end def _show_actions
|
|
|
|
def _reset_order_state (self) :
|
|
row_data = self._view.selectedItems ()
|
|
if row_data :
|
|
bno = row_data [0].text ()
|
|
r = QtWidgets.QMessageBox.question \
|
|
( self, self.tr ("Fehler")
|
|
, self.tr
|
|
( "Soll der Status wirklich auf In Bearbeitung "
|
|
"gesetzt werden?"
|
|
)
|
|
)
|
|
if r == QtWidgets.QMessageBox.No :
|
|
return
|
|
with schema.orm.db_session () :
|
|
order = schema.Order.get (basket_no = bno, active = True)
|
|
order.state = 10
|
|
self.update_order (order, False)
|
|
App_State.Create_Action \
|
|
( 15
|
|
, f"Status wird auf 10 gesetzt"
|
|
, order
|
|
)
|
|
# end def _reset_order_state
|
|
|
|
# end class Order_List
|
|
|
|
class Order_Detail (_With_Table_Widget_) :
|
|
|
|
settings_group = "order-detail"
|
|
Header = "Auftrags Detail"
|
|
Columns = \
|
|
("Position", "Artikel", "Preis")
|
|
|
|
# end class Order_Detail
|
|
|
|
class Order_Display (QtWidgets.QSplitter) :
|
|
|
|
def __init__ (self, parent) :
|
|
super ().__init__ (parent)
|
|
self._order_list = Order_List ()
|
|
self._order_detail = Order_Detail ()
|
|
self.addWidget (self._order_list)
|
|
self.addWidget (self._order_detail)
|
|
self.orders = {}
|
|
# end def __init__
|
|
|
|
def update_orders (self) :
|
|
orders = set (self.orders.keys ())
|
|
with schema.orm.db_session :
|
|
for o in schema.Order.select (active = True) :
|
|
db_lc = o.actions.order_by (schema.Action.date).first ().date
|
|
if o.basket_no not in self.orders :
|
|
self._order_list.update_order (o, True)
|
|
self.orders [o.basket_no] = o
|
|
o.last_changed = db_lc
|
|
else :
|
|
if db_lc > self.orders [o.basket_no].last_changed :
|
|
self._order_list.update_order (o, False)
|
|
self.orders [o.basket_no].last_changed = db_lc
|
|
orders.discard (o.basket_no)
|
|
self._order_list.remove_orders (orders)
|
|
for o in orders :
|
|
self.orders.pop (o, None)
|
|
# end def update_orders
|
|
|
|
def save_settings (self, settings) :
|
|
settings.beginGroup ("order-display")
|
|
settings.setValue ("geometry", self.saveGeometry ())
|
|
settings.setValue ("windowState", self.saveState ())
|
|
settings.endGroup ()
|
|
self._order_list .save_settings (settings)
|
|
self._order_detail.save_settings (settings)
|
|
# end def save_settings
|
|
|
|
def restore_settings (self, settings) :
|
|
settings.beginGroup ("order-display")
|
|
self.restoreGeometry (settings.value ("geometry" ))
|
|
self.restoreState (settings.value ("windowState"))
|
|
settings.endGroup ()
|
|
self._order_list .restore_settings (settings)
|
|
self._order_detail.restore_settings (settings)
|
|
# end def restore_settings
|
|
|
|
# end class Order_Display |