Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
lib-py-b2b / acknowledge.py
Size: Mime:
from os import environ
import datetime
import logging
from boto3 import resource
from botocore.exceptions import ClientError
from validators import url
from .errors import AcknowledgementFailedError, AcknowledgementFailedWarning
from .profile import Profile
from .shopify import CancelOrderAction

order_table = environ['order_table'] if 'order_table' in environ else 'test.b2b.Orders'
log_level = logging.getLevelName(environ['LOG_LEVEL']) if 'LOG_LEVEL' in environ else logging.INFO
logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(log_level)

MAX_RETRY_COUNT = 5


class Acknowledgement:
    def __init__(self, order):
        self.order = order
        self.profile = Profile.profile_for(customer=self.order['customer_edi_id'])

    def __record_status(self, was_successful, msg=None):
        try:
            dynamodb_resource = resource('dynamodb', region_name='us-east-1')
            table = dynamodb_resource.Table(order_table)
            oid = self.order['id']

            logger.debug(f"Updating order acknowledgement status (success: {was_successful}) for order {oid}")
            if was_successful:
                response = table.update_item(
                    Key={'id': oid},
                    UpdateExpression="set acknowledged = :a, acknowledged_date = :d, acknowledgement_sent = :s",
                    ExpressionAttributeValues={
                        ':s': True,
                        ':d': datetime.datetime.now().isoformat(),
                        ':a': True
                    },
                    ReturnValues="UPDATED_NEW"
                )
            else:
                retry_count = self.order['acknowledged_send_retry_count'] if 'acknowledged_send_retry_count' in self.order else 0
                retry_count = retry_count + 1

                response = table.update_item(
                    Key={'id': oid},
                    UpdateExpression="set acknowledged = :s, acknowledgement_last_error = :m, "
                                     "acknowledgement_last_error_date = :d, acknowledged_send_retry_count = :r",
                    ExpressionAttributeValues={
                        ':s': False,
                        ':m': msg,
                        ':r': retry_count,
                        ':d': datetime.datetime.now().isoformat()
                    },
                    ReturnValues="UPDATED_NEW"
                )

            return response
        except ClientError as ce:
            logger.error(ce)
            if ce.response['Error']['Code'] != 'ConditionalCheckFailedException':
                raise ce
        except Exception as e:
            logger.error(e)

    def is_required(self):
        try:
            if self.profile.integration_config.send_ack_to_url_from_order:
                notification_url = self.order['notification_urls']['order_acknowledgement']
                if url(notification_url) is not True:
                    return False

            retry_count = self.order['acknowledged_send_retry_count'] if 'acknowledged_send_retry_count' in self.order else 0
            if ('acknowledged' not in self.order or self.order['acknowledged'] is False) \
                    and retry_count < MAX_RETRY_COUNT:
                return True
            return False
        except KeyError:
            return False

    def notify(self):
        if self.is_required():
            if self.profile.integration_config.send_ack_to_url_from_order:
                try:
                    StandardAcknowledgementAction(self.order).send()
                    self.__record_status(was_successful=True)
                    logging.info(f"Sent order acknowledgement for order: [{self.order['id']}] ")
                    return self.order
                except Exception as e:
                    ackf = AcknowledgementFailedWarning(e)
                    self.__record_status(was_successful=False, msg=str(ackf))
                    logging.warning(f"Failed to send acknowledgement for order: [{self.order['id']}]. "
                                    f"Will retry on next scheduled interval. ", ackf)
                    logging.warning(ackf)

            if self.profile.integration_config.cancel_order_on_reject and self.order['order_status'] == 'REJECTED':
                try:
                    CancelOrderAction(self.order).send()
                    logging.info(f"Canceled Orders: [{self.order['id']}]")
                except Exception as e:
                    logging.error(f"Failed to cancel Orders: [{self.order['id']}]")
                    logging.error(e)

        else:
            if 'acknowledged' not in self.order or self.order['acknowledged'] is False:
                retry_count = self.order['acknowledged_send_retry_count'] if 'acknowledged_send_retry_count' in self.order else 0
                if retry_count >= MAX_RETRY_COUNT:
                    afe = AcknowledgementFailedError(f"Maximum retries exhausted trying to send acknowledgement "
                                                     f"for order: [{self.order['id']}].")
                    logging.error(afe)
                else:
                    afe = AcknowledgementFailedError(f"Acknowledgment not required for order that is not acknowledged. "
                                                     f"order: [{self.order['id']}]")
                    logging.error(afe)


# Moved here to avoid silly python circular import problems
from .standard import StandardAcknowledgementAction