# -*- coding: utf-8 -*- import time, datetime import hashlib from odoo import models from typing import Optional import socket import os import logging import qrcode from reportlab.pdfgen import canvas from reportlab.lib.units import inch from PyPDF2 import PdfFileReader, PdfFileWriter from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont class Common(models.Model): _name = 'sf.sync.common' _description = u'公用类' def get_headers(self, token, secret_key): ''' 获取requests中的heardes参数 ''' timestamp = int(time.time()) check_str = '%s%s%s' % (token, timestamp, secret_key) check_sf_str = hashlib.sha1(check_str.encode('utf-8')).hexdigest() headers = {'TOKEN': token, 'TIMESTAMP': str(timestamp), 'checkstr': check_sf_str} return headers def get_add_time(self, parse_time): """ 把时间增加8小时 :return: """ dt = datetime.datetime.strptime(parse_time, "%Y-%m-%d %H:%M:%S") d = dt + datetime.timedelta(hours=8) nTime = d.strftime("%Y-%m-%d %H:%M:%S") return nTime class PrintingUtils(models.AbstractModel): _name = 'printing.utils' _description = 'Utility class for printing functionalities' def generate_zpl_code(self, code): # 实现生成ZPL代码的逻辑 # 初始化ZPL代码字符串 zpl_code = "^XA\n" zpl_code += "^CW1,E:SIMSUN.TTF^FS\n" zpl_code += "^CI28\n" # 设置二维码位置 zpl_code += "^FO50,50\n" # 调整二维码位置,使其与资产编号在同一行 zpl_code += f"^BQN,2,6^FDLM,B0093{code}^FS\n" # 设置资产编号文本位置 zpl_code += "^FO300,60\n" # 资产编号文本的位置,与二维码在同一行 zpl_code += "^A1N,45,45^FD编码名称: ^FS\n" # 设置{code}文本位置 # 假设{code}文本需要位于资产编号和二维码下方,中间位置 # 设置{code}文本位置并启用自动换行 zpl_code += "^FO300,120\n" # {code}文本的起始位置 zpl_code += "^FB400,4,0,L,0\n" # 定义一个宽度为500点的文本框,最多4行,左对齐 zpl_code += f"^A1N,40,40^FD{code}^FS\n" # 在{code}文本框周围绘制线框 # 假设线框的外部尺寸为宽度500点,高度200点 # zpl_code += "^FO300,110^GB500,200,2^FS\n" # 绘制线框,边框粗细为2点 zpl_code += "^PQ1,0,1,Y\n" zpl_code += "^XZ\n" return zpl_code def send_to_printer(self, host, port, zpl_code): # 实现发送ZPL代码到打印机的逻辑 # 将ZPL代码转换为字节串 print('zpl_code', zpl_code) zpl_bytes = zpl_code.encode('utf-8') print(zpl_bytes) # 创建socket对象 mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: mysocket.connect((host, port)) # 连接到打印机 mysocket.send(zpl_bytes) # 发送ZPL代码 print("ZPL code sent to printer successfully.") except Exception as e: print(f"Error with the connection: {e}") finally: mysocket.close() # 关闭连接 def print_qr_code(self, lot_name, host, port): # 实现打印二维码的逻辑 # 这里需要传入 lot_name 参数,因为我们不能直接访问 self.lot_id.name zpl_code = self.generate_zpl_code(lot_name) # 发送ZPL代码到打印机 # host = "192.168.50.110" # 可以作为参数传入,或者在此配置 # port = 9100 # 可以作为参数传入,或者在此配置 self.send_to_printer(host, port, zpl_code) def add_qr_code_to_pdf( self, pdf_path:str, content:str, qr_code_buttom_text:Optional[str]=False, buttom_text:Optional[str]=False, ): """ 在PDF文件中添加二维码 :param pdf_path: PDF文件路径 :param content: 二维码内容 :param qr_code_buttom_text: 二维码下方文字 :param buttom_text: 正文下方文字 :return: 是否成功 """ if not os.path.exists(pdf_path): logging.warning(f'PDF文件不存在: {pdf_path}') return False # 生成二维码 qr = qrcode.QRCode(version=1, box_size=10, border=5) qr.add_data(str(content)) qr.make(fit=True) qr_img = qr.make_image(fill_color="black", back_color="white") # 保存二维码为临时文件 qr_temp_path = '/tmp/qr_temp.png' qr_img.save(qr_temp_path) # 创建一个临时PDF文件路径 output_temp_path = '/tmp/output_temp.pdf' try: # 使用reportlab创建一个新的PDF # 注册中文字体 font_paths = [ "/usr/share/fonts/chinese/simsun.ttc", # Windows系统宋体 "c:/windows/fonts/simsun.ttc", # Windows系统宋体另一个位置 "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", # Linux Droid字体 "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", # 文泉驿正黑 "/usr/share/fonts/chinese/TrueType/simsun.ttc", # 某些Linux发行版位置 ] font_found = False for font_path in font_paths: if os.path.exists(font_path): try: pdfmetrics.registerFont(TTFont('SimSun', font_path)) font_found = True break except: continue # 读取原始PDF with open(pdf_path, "rb") as original_file: existing_pdf = PdfFileReader(original_file) output = PdfFileWriter() # 处理最后一页 last_page = existing_pdf.getNumPages() - 1 page = existing_pdf.getPage(last_page) # 获取页面尺寸 page_width = float(page.mediaBox.getWidth()) page_height = float(page.mediaBox.getHeight()) # 创建一个新的PDF页面用于放置二维码 c = canvas.Canvas(output_temp_path, pagesize=(page_width, page_height)) # 设置字体 if font_found: c.setFont('SimSun', 10) # 增大字体大小到14pt else: # 如果没有找到中文字体,使用默认字体 c.setFont('Helvetica', 10) logging.warning("未找到中文字体,将使用默认字体") # 在右下角绘制二维码,预留边距 qr_size = 1.5 * inch # 二维码大小为2英寸 margin = 0.1 * inch # 边距为0.4英寸 qr_y = margin + 20 # 将二维码向上移动一点,为文字留出空间 c.drawImage(qr_temp_path, page_width - qr_size - margin, qr_y, width=qr_size, height=qr_size) if qr_code_buttom_text: # 在二维码下方绘制文字 text = qr_code_buttom_text text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 10) # 准确计算文字宽度 text_x = page_width - qr_size - margin + (qr_size - text_width) / 2 # 文字居中对齐 text_y = margin + 20 # 文字位置靠近底部 c.drawString(text_x, text_y, text) # 设置字体 if font_found: c.setFont('SimSun', 12) # 增大字体大小到14pt else: # 如果没有找到中文字体,使用默认字体 c.setFont('Helvetica', 120) logging.warning("未找到中文字体,将使用默认字体") if buttom_text: # 在下方中间添加文字 text = buttom_text text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 12) # 准确计算文字宽度 text_x = (page_width - text_width) / 2 # 文字居中对齐 text_y = margin + 20 # 文字位置靠近底部 c.drawString(text_x, text_y, text) c.save() # 读取带有二维码的临时PDF with open(output_temp_path, "rb") as qr_file: qr_pdf = PdfFileReader(qr_file) qr_page = qr_pdf.getPage(0) # 合并原始页面和二维码页面 page.mergePage(qr_page) # 添加剩余的页面 for i in range(0, last_page): output.addPage(existing_pdf.getPage(i)) output.addPage(page) # 保存最终的PDF到一个临时文件 final_temp_path = pdf_path + '.tmp' with open(final_temp_path, "wb") as output_file: output.write(output_file) # 替换原始文件 os.replace(final_temp_path, pdf_path) return True finally: # 清理临时文件 if os.path.exists(qr_temp_path): os.remove(qr_temp_path) if os.path.exists(output_temp_path): os.remove(output_temp_path)