Repository URL to install this package:
| 
      
     
      
        
        
        Version: 
        
         
  
        
    
          
          0.4.184  ▾
        
         
  
      
        
      
  
      
  
     | 
    
    lib-py-b2b
  
    /
        print.py
    | 
|---|
import boto3
from botocore.exceptions import ClientError
from .fulfillment import Fulfillment
from .profile import Profile
import json
from datetime import datetime
import logging
from pprint import pformat
from .carrier import CarrierType
import binascii
import socket
from .errors import InvalidLabelPrintRequestError, LabelPrintError
from os import environ
logger = logging.getLogger(__name__)
class Printer:
    @staticmethod
    def for_(customer_edi_id: str):
        profile = Profile.profile_for(customer_edi_id)
        name = profile.fulfillment_config.fedex_api_config.printer_name
        ip_address = profile.fulfillment_config.fedex_api_config.printer_ip_address
        port = int(profile.fulfillment_config.fedex_api_config.printer_port)
        return Printer(name=name, address=ip_address, port=port)
    def __init__(self, name: str, address: str, port: int):
        self.name = name
        self.address = address
        self.port = port
class PrintRequest:
    LABEL_PRINT_QUEUE = environ['LABEL_PRINT_QUEUE'] if 'LABEL_PRINT_QUEUE' in environ else 'B2B_LABEL_PRINT_QUEUE_DEV'
    LABEL_PRINT_DLQ = environ['LABEL_PRINT_DLQ'] if 'LABEL_PRINT_DLQ' in environ else 'B2B_LABEL_PRINT_DLQ_DEV'
    @staticmethod
    def setup_queues():
        sqs = boto3.resource('sqs')
        dlq = sqs.create_queue(QueueName=PrintRequest.LABEL_PRINT_DLQ)
        redrive_policy = {
            'deadLetterTargetArn': dlq.attributes['QueueArn'],
            'maxReceiveCount': '10'
        }
        queue = sqs.create_queue(QueueName=PrintRequest.LABEL_PRINT_QUEUE,
                                      Attributes={'DelaySeconds': '0',
                                                  'VisibilityTimeout': '60',
                                                  'RedrivePolicy': json.dumps(redrive_policy)})
        return queue
    @staticmethod
    def __get_print_queue():
        try:
            sqs = boto3.resource('sqs')
            return sqs.get_queue_by_name(QueueName=PrintRequest.LABEL_PRINT_QUEUE)
        except ClientError as ce:
            if ce.response['Error']['Code'] == 'AWS.SimpleQueueService.NonExistentQueue':
                return PrintRequest.setup_queues()
            else:
                logger.exception("Error received trying to access the print queue.")
                return None
    @staticmethod
    def create(printer: Printer, fulfillment):
        _fulfillment = Fulfillment.for_(fulfillment)
        print_request = {
            'fulfillment_id': _fulfillment['id'],
            'printer_address': printer.address,
            'printer_port': printer.port,
            'request_time': datetime.utcnow().isoformat()
        }
        logger.debug(f"Sending print request {pformat(print_request)} to {PrintRequest.LABEL_PRINT_QUEUE}")
        queue = PrintRequest.__get_print_queue()
        response = queue.send_message(MessageBody=json.dumps(print_request))
        return response['MessageId']
class PrintRequestHandler:
    def __print_label(self, fulfillment_id, labels, printer_address, printer_port):
        for label in labels:
            for i in range(0, int(label['copies'])):
                for image in label['parts']:
                    label_binary_data = binascii.a2b_base64(image)
                    try:
                        s = socket.create_connection(address=(printer_address, printer_port), timeout=60)
                    except socket.error as se:
                        logger.error(f"Unable to connect to printer {printer_address}:{printer_port} for fulfillment {fulfillment_id}.", se)
                        raise LabelPrintError(f"Unable to connect to printer {printer_address}:{printer_port} for fulfillment {fulfillment_id}.") from se
                    try:
                        s.send(label_binary_data)
                    except socket.error as se:
                        logger.error(f"Unable to print labels for fulfillment {fulfillment_id}.", se)
                        raise LabelPrintError(f"Unable to print labels for fulfillment {fulfillment_id}.") from se
                    finally:
                        s.close()
    def handle_print_request(self, record):
        pr = json.loads(record.body)
        logger.debug(f"Received print request {pformat(pr)}")
        fulfillment_id = pr['fulfillment_id']
        _fulfillment = Fulfillment.for_(fulfillment_id)
        carrier_type = CarrierType(_fulfillment.get('carrier_type', _fulfillment.get('carrier_type', CarrierType.FEDEX_SHIP_MGR.value)))
        if carrier_type == CarrierType.FEDEX_API:
            if 'labels' in _fulfillment:
                logger.info(f"Printing labels for request {pformat(pr)}")
                self.__print_label(fulfillment_id=_fulfillment['id'],
                                   labels=_fulfillment['labels'],
                                   printer_address=pr['printer_address'],
                                   printer_port=pr['printer_port'])
            else:
                logger.warning(f"Attempted to print labels for fulfillment {_fulfillment['id']} and it had no labels.")
        else:
            raise InvalidLabelPrintRequestError(f"The carrier type {carrier_type} on fulfillment {_fulfillment['id']} does not "
                                                f"support label printing.")