2********************************************************************************
4@brief create bon text and send to printer
5********************************************************************************
14from typing
import Any, TYPE_CHECKING
21from escpos.printer
import Dummy
25 write_com_port_settings, write_paper_width_settings, thread_loop, S_UNIT, get_computer_name, EUser, get_serial_ports, \
35log = logging.getLogger(__title__)
40 @brief Supported printers
48 EPrinter.EPSON: {EPaper.WIDTH_58_MM.name: 34,
49 EPaper.WIDTH_80_MM.name: 48},
50 EPrinter.PROLIFIC: {EPaper.WIDTH_58_MM.name: 30,
51 EPaper.WIDTH_80_MM.name: 44},
52 EPrinter.DEFAULT: {EPaper.WIDTH_58_MM.name: 30,
53 EPaper.WIDTH_80_MM.name: 44}
56F_PRINTER_SLEEP_TIME = 0.2
57F_PRINTER_PRINT_DELAY = 0.75
58S_PRINT_ERROR_FILE =
"FailedPrints.csv"
63 @brief Checks if a string is a network address.
64 @param s : string to check
65 @return status if is ip address
67 return re.fullmatch(
r'(\d{1,3}\.){3}\d{1,3}(:\d+)?', s)
is not None
72 @brief Class create bons and printout.
73 @param ui : main window object
93 def set_header(self, s_header1: str =
"", s_header2: str =
"") ->
None:
96 @param s_header1 : first line in bon header
97 @param s_header2 : second line in bon header
104 @brief Initialize COM Port.
106 l_present_ports = get_serial_ports()
110 for port, name, _
in l_present_ports:
111 log.debug(
"Present Port: %s (%s)", port, name)
112 b_com_port_available =
True
114 if b_com_port_available:
116 for printer, _value
in D_PRINTER.items():
117 if name.startswith(printer.name):
119 if b_com_port_available:
122 log.debug(
"Available Port: %s (%s)", port, name)
127 self.
ui.set_status([f
"Select COM Port not available: {self.s_select_com_port}",
128 f
"Ausgewählter COM Port nicht verfügbar: {self.s_select_com_port}"],
True)
134 @brief Update COM port menu
137 if not all_actions_add:
138 self.
ui.set_status([
"Too much COM Ports available",
"Zu viele COM Ports verfügbar"],
True)
142 @brief Update COM Port of printer
143 @param s_com_port : selected COM port
151 if s_com_port
is None:
152 self.
ui.set_status([
"Printer disabled",
"Drucker deaktiviert"])
154 self.
ui.set_status([f
"Select Printer: {s_com_port}", f
"Ausgewählter Drucker: {s_com_port}"])
161 self.
ui.set_status([
"Can not change COM port. Print queue is not empty.",
162 "COM Port kann nicht geändert werden. Es befinden sich Ausdrucke in der Warteschlange."],
True)
167 @brief Update paper width.
168 @param i_paper_width : paper width in "mm"
169 @param b_statusbar_info : [True] show update info on status bar; [False] show not
172 if i_paper_width == EPaper.WIDTH_80_MM.value:
179 self.
ui.set_status([f
"Select Paper width: {i_paper_width} mm",
180 f
"Gewählte Papierbreite: {i_paper_width} mm"])
182 def add_to_queue(self, l_items: list[Item], i_user_pos: int, f_total_price: float) ->
None:
184 @brief Add item to bon queue.
185 @param l_items : list of items to add
186 @param i_user_pos : user position
187 @param f_total_price : total price
189 s_user = l_items[0].user
193 b_print_article = self.
ui.model.c_config.get_print_article_status()
195 b_print_actual_article = self.
ui.model.c_config.get_item_print_status(item.pos)
if b_print_article
else False
196 b_print = b_print_actual_article
199 self.
ui.set_status([f
"Print Articles for user {s_user}",
200 f
"Artikel werden gedruckt für Benutzer {s_user}"])
202 b_save_report =
False
203 self.
ui.set_status([f
"{self.s_select_com_port} will print and is not available",
204 f
"{self.s_select_com_port} ist zum Drucken nicht verfügbar"],
True)
206 self.
ui.set_status([f
"Articles saved to user {s_user}",
207 f
"Artikel gesichert für Benutzer {s_user}"])
210 self.
ui.model.c_report.write_data_to_print_file(l_items, i_user_pos, f_total_price, self.
s_select_com_port)
214 @brief Add text to report queue.
215 @param s_text : text to print out
222 @brief Open drawer trigger
227 def network_print(self, network_printer_ip: str, print_content: bytes) -> bool:
230 @param network_printer_ip : IP address of printer
231 @param print_content : content to print
232 @return success status
236 with socket.socket(socket.AF_INET, socket.SOCK_STREAM)
as s:
238 s.connect((network_printer_ip, 9100))
239 s.sendall(print_content)
241 except socket.timeout:
242 self.
ui.set_status([
"Printout to network printer failed",
"Ausdruck auf Netzwerkdrucker fehlgeschlagen"],
True, b_thread=
True)
245 self.
ui.set_status([
"Printout to network printer failed - Error unknown",
"Ausdruck auf Netzwerkdrucker fehlgeschlagen - Fehler unbekannt"],
True, b_thread=
True)
251 @brief Printer loop to check for items to print out.
253 s_actual_used_com_port =
None
259 if (c_serial_port
is not None)
and c_serial_port.isOpen():
260 c_serial_port.close()
263 if c_serial_port
is not None:
264 if not c_serial_port.isOpen():
269 network_printer_ip =
None
271 log.debug(
"Create Bon: %s", item)
272 for _
in range(item.amount):
273 if network_printer_ip:
277 with open(S_PRINT_ERROR_FILE, mode=
"a+", encoding=
"utf-8", newline=
"")
as file:
278 writer = csv.writer(file, delimiter=
";")
279 price = float(item.price_total) / item.amount
280 s_price = f
"{price:.2f}"
281 l_item = [1, item.name, item.pos, item.group, s_price, item.user, item.date, network_printer_ip]
282 writer.writerow(l_item)
284 c_serial_port.write(bon)
285 log.debug(
"Print Bon")
286 time.sleep(F_PRINTER_PRINT_DELAY)
287 b_check_open_drawer =
True
288 if b_check_open_drawer:
294 self.
ui.set_status(
"None printer will print. Disable printer and clear queue.",
True, b_thread=
True)
300 if (c_serial_port
is not None)
and c_serial_port.isOpen():
301 c_serial_port.close()
302 time.sleep(F_PRINTER_SLEEP_TIME)
306 @brief Printer Thread to check for items to print out.
308 thread_loop(self,
"Printer")
312 @brief Create bon code for printer.
313 @param item : item to create bon
314 @return return bon code for printer
317 s_pay = f
"{S_UNIT} {item.price}".rjust(self.
i_line_break)
321 c_dummy.set_with_default()
324 c_dummy.text(f
"{s_header1}\n")
327 c_dummy.text(f
"{s_header2}\n")
328 c_dummy.text(f
"{s_info}\n\n")
329 c_dummy.set(double_width=
True, double_height=
True)
330 c_dummy.text(f
"{s_product}")
331 c_dummy.set_with_default()
332 if (item.user != EUser.FREE)
or self.
ui.model.c_config.get_print_free_price_status():
333 c_dummy.text(f
"\n{s_pay}")
336 c_dummy.cut(mode=
"PART")
337 return c_dummy.output
341 @brief Create report text for printer
343 @return return report code for printer
346 c_dummy.set_with_default()
348 c_dummy.cut(mode=
"PART")
349 return c_dummy.output
353 @brief Create open drawer code for printer
354 @return return open drawer code for printer
357 c_dummy.cashdraw(pin=2)
358 return c_dummy.output
362 @brief Open drawer if required
363 @param serial_port : serial port
366 log.debug(
"Open Cash Drawer")
Class create bons and printout.
None add_to_report(self, str s_text)
Add text to report queue.
None check_open_drawer(self, serial.Serial serial_port)
Open drawer if required.
Any create_bon(self, Item item)
Create bon code for printer.
None update_paper_width(self, int i_paper_width, bool b_statusbar_info=True)
Update paper width.
Any create_report_bon(self, str s_text)
Create report text for printer.
list l_available_port_names
Any create_open_drawer(self)
Create open drawer code for printer.
None run(self)
Printer Thread to check for items to print out.
None init_com_port(self)
Initialize COM Port.
None loop(self)
Printer loop to check for items to print out.
queue.Queue[Item] bon_queue
queue.Queue[str] report_queue
None set_header(self, str s_header1="", str s_header2="")
Set bon header.
bool b_select_com_port_available
bool network_print(self, str network_printer_ip, bytes print_content)
Network print.
None __init__(self, "MainWindow" ui)
None open_drawer(self)
Open drawer trigger.
None update_com_port(self, str s_com_port)
Update COM Port of printer.
None update_com_port_menu(self)
Update COM port menu.
None add_to_queue(self, list[Item] l_items, int i_user_pos, float f_total_price)
Add item to bon queue.
bool is_ip_address(str s)
Checks if a string is a network address.