Example #1
0
 def __init__(self, context, request):
     self.context = context
     self.request = request
     self.request.set('disable_border', True)
     registry = getUtility(IRegistry)
     self.shop_config = registry.forInterface(IShopConfiguration)
     self.mhost = IMailHostAdapter(self.context)
     self.order_storage = getUtility(IOrderStorage,
                                     name=self.shop_config.order_storage)
     self.supplier_filter = None
     self.status_filter = None
     super(OrderManagerView, self).__init__(context, request)
Example #2
0
 def __init__(self, context, request):
     self.context = context
     self.request = request
     self.request.set('disable_border', True)
     registry = getUtility(IRegistry)
     self.shop_config = registry.forInterface(IShopConfiguration)
     self.mhost = IMailHostAdapter(self.context)
     self.order_storage = getUtility(IOrderStorage,
                                     name=self.shop_config.order_storage)
     self.supplier_filter = None
     self.status_filter = None
     super(OrderManagerView, self).__init__(context, request)
Example #3
0
class OrderManagerView(BrowserView):
    """Lists orders stored in a IOrderStorage
    """

    template = ViewPageTemplateFile('templates/order_manager.pt')
    change_status_tmpl = ViewPageTemplateFile('templates/status.pt')

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.request.set('disable_border', True)
        registry = getUtility(IRegistry)
        self.shop_config = registry.forInterface(IShopConfiguration)
        self.mhost = IMailHostAdapter(self.context)
        self.order_storage = getUtility(IOrderStorage,
                                        name=self.shop_config.order_storage)
        self.supplier_filter = None
        self.status_filter = None
        super(OrderManagerView, self).__init__(context, request)


    def __call__(self):
        from_date, to_date = self.parse_date_range()
        self.supplier_filter = self.request.form.get('supplier',
            'all_suppliers')
        self.status_filter = self.request.form.get('form.widgets.status_filter', 'all')
        self.order_results = self.getOrders(from_date, to_date)
        if self.request.form.get('filter'):
            return self.__of__(self.context).template()
        elif self.request.form.get('download_csv'):
            return self.download_csv()
        elif self.request.form.get('cancel_orders'):
            return self.cancel_orders()
        elif self.request.form.get('change_status_step1'):
            return self.__of__(self.context).change_status_tmpl()
        elif self.request.form.get('change_status'):
            return self.change_status()
        else:
            return self.__of__(self.context).template()


    def parse_date_range(self):
        """Parse the from_date and to_date strings,
        assuming the jQuery UI datepicker widget always
        stores them in the request in the "%d.%m.%Y"
        format.
        """

        try:
            from_date = strptime(self.request.form.get(
                'from_date', ''), "%d.%m.%Y").date()
        except ValueError:
            from_date = date(2001, 1, 1)
        try:
            to_date = strptime(self.request.form.get(
                'to_date', ''), "%d.%m.%Y").date()
        except ValueError:
            to_date = date(2100, 1, 1)
        return (from_date, to_date)


    def getSuppliers(self):
        catalog = getToolByName(self.context, 'portal_catalog')
        brains = catalog(portal_type="Supplier")
        results = [dict(name=b.Title, email=b.email) for b in brains]
        return results

    def download_csv(self):
        """Returns a CSV file containing the shop orders
        """

        filename = "orders.csv"
        stream = cStringIO.StringIO()
        csv_writer = csv.writer(stream, dialect='excel', delimiter=';',
                                quotechar='"', quoting=csv.QUOTE_MINIMAL)
        core_cols = ['order_id',
                      'title',
                      'status',
                      'total',
                      'date',
                      'customer_title',
                      'customer_firstname',
                      'customer_lastname',
                      'customer_company',
                      'customer_email',
                      'customer_street1',
                      'customer_street2',
                      'customer_phone',
                      'customer_zipcode',
                      'customer_city',
                      'customer_shipping_address',
                      'customer_country',
                      'customer_comments']

        # Create union of core_cols + all_cols to retain order
        all_cols = self.order_storage.getFieldNames()
        columns = core_cols + filter(lambda x:x not in core_cols, all_cols)
        cart_cols = ['sku_code', 'quantity', 'title', 'price',
                     'item_total', 'supplier_name', 'supplier_email']

        column_titles = [COLUMN_TITLES[col].decode('utf-8').encode('cp1252') for col in columns + cart_cols]
        # Write header row
        csv_writer.writerow(column_titles)

        for order in self.order_results:
            order_data = [getattr(order, attr, '') for attr in columns]

            # Get the total via getTotal accessor to convert it to Decimal
            order_data[columns.index('total')] = order.getTotal()

            for i, value in enumerate(order_data):
                if isinstance(value, unicode):
                    order_data[i] = value.encode('cp1252')

            for cart_item in order.cartitems:
                cart_data = [cart_item.sku_code,
                            cart_item.quantity,
                            cart_item.title,
                            cart_item.getPrice(),
                            cart_item.getTotal(),
                            cart_item.supplier_name,
                            cart_item.supplier_email]

                for i, value in enumerate(cart_data):
                    if isinstance(value, unicode):
                        cart_data[i] = value.encode('cp1252')

                csv_writer.writerow(order_data + cart_data)

        RESPONSE = self.request.RESPONSE
        header_value = contentDispositionHeader('attachment',
                                                'cp1252',
                                                filename=filename)
        if not DEBUG:
            RESPONSE.setHeader("Content-Disposition", header_value)
            RESPONSE.setHeader("Content-Type",
                           'text/comma-separated-values;charset=%s' % 'cp1252')
        else:
            RESPONSE.setHeader("Content-Type",
                           'text/plain; charset=%s' % 'cp1252')

        stream.seek(0)
        return stream.read()

    def cancel_orders(self):
        """Cancel orders by their order_ids
        """
        context = aq_inner(self.context)
        ptool = getToolByName(context, 'plone_utils')
        order_storage = self.getOrderStorage()

        orders = self.request.form.get('orders', [])
        for order_id in orders:
            try:
                order_id = int(order_id)
            except ValueError:
                # Invalid order_id - continue with next one
                continue
            order_storage.cancelOrder(order_id)
        msg = _(u'msg_order_cancelled',
                default=u"${no_orders} orders cancelled.",
                mapping={ u"no_orders" : len(orders)})
        ptool.addPortalMessage(msg, 'info')
        self.request.response.redirect("%s/order_manager" % context.absolute_url())

    def change_status(self):
        """Change status of several orders at once
        """
        context = aq_inner(self.context)
        ptool = getToolByName(context, 'plone_utils')
        order_storage = self.getOrderStorage()

        orders = self.request.form.get('orders', [])
        new_status = self.request.form.get('form.widgets.status', None)

        # Change status of the orders
        for order_id in orders:
            try:
                order_id = int(order_id)
            except ValueError:
                # Invalid order_id - continue with next one
                continue
            order = order_storage.getOrder(order_id)
            order.status = int(new_status)

        msg = _(u'msg_status_changed',
                default=u"Changed status for ${no_orders} orders.",
                mapping={ u"no_orders" : len(orders)})
        ptool.addPortalMessage(msg, 'info')
        return self.template()


    def getOrders(self, from_date=None, to_date=None):
        order_storage = self.order_storage
        all_orders = order_storage.getAllOrders()

        if any([from_date and to_date, self.supplier_filter, self.status_filter]):
            # Filter orders
            orders = []
            for order in all_orders:
                suppliers = [item.supplier_name for item in order.cartitems]
                if (self.supplier_filter in suppliers
                or self.supplier_filter in ["all_suppliers", "", None]) \
                and self.status_filter == str(order.status) \
                or self.status_filter == "all" \
                and from_date <= order.date.date() \
                and to_date >= order.date.date():
                    orders.append(order)
        else:
            orders = all_orders
        return orders

    def getOrder(self, order_id):
        order_storage = self.order_storage
        order = order_storage.getOrder(order_id)
        return order

    def getOrderStorage(self):
        return self.order_storage

    def addOrder(self):
        """Add a new Order and return the order id.
        """

        session = self.context.REQUEST.SESSION

        # check for cart
        cart_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'cart_view')
        cart_data = cart_view.cart_items()

        # check for customer data
        customer_data = session.get(SESSION_ADDRESS_KEY, {})
        if not customer_data:
            raise MissingCustomerInformation

        # check for shipping address
        shipping_data = session.get(SESSION_SHIPPING_KEY, {})
        if not shipping_data:
            raise MissingShippingAddress

        # check for order confirmation
        if not session.get('order_confirmation', None):
            raise MissingOrderConfirmation

        # check for payment processor
        payment_processor_step_groups = getAdapters(
                                        (self.context, self.request, self),
                                        IPaymentProcessorStepGroup)

        selected_pp_step_group = self.shop_config.payment_processor_step_group
        for name, step_group_adapter in payment_processor_step_groups:
            if name == selected_pp_step_group:
                payment_processor_steps = step_group_adapter.steps

        if not len(payment_processor_steps) == 0 \
            and not session.get('payment_processor_choice', None):
            raise MissingPaymentProcessor

        # change security context to owner
        user = self.context.getWrappedOwner()
        newSecurityManager(self.context.REQUEST, user)

        order_storage = self.order_storage
        order_id = order_storage.createOrder(status=ONLINE_PENDING_KEY,
                                             date=datetime.now(),
                                             customer_data=customer_data,
                                             shipping_data=shipping_data,
                                             total=cart_view.cart_total(),
                                             cart_data=cart_data)
        order_storage.flush()

        noSecurityManager()

        return order_id

    def sendOrderMails(self, order_id):
        """Send order confirmation and notification mails for the order with
        the specified order_id.
        """

        order = self.order_storage.getOrder(order_id)

        ltool = getToolByName(self.context, 'portal_languages')
        lang = ltool.getPreferredLanguage()

        # Send order confirmation to customer
        self._send_customer_mail(order, lang)

        # Send order notification to supplier(s)
        suppliers = []
        for item_type in order.cartitems:
            if not (item_type.supplier_name == '' \
                or item_type.supplier_email == ''):
                for email_address in item_type.supplier_email.split(','):
                    suppliers.append((item_type.supplier_name,
                                      email_address.strip()))
        unique_suppliers = set(suppliers)
        for supplier in unique_suppliers:
            self._send_supplier_mail(supplier, order)

        # Send order notification to shop owner
        if self.shop_config.always_notify_shop_owner:
            self._send_owner_mail(order)

        return

    def _send_owner_mail(self, order):
        """Send order notification to shop owner.
        """
        show_prices = self.show_prices(order)
        mail_to = formataddr(("Shop Owner", self.shop_config.shop_email))
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        customer_address = formataddr((customer_name, order.customer_email))
        mail_subject = '[%s] Order %s by %s' % (self.shop_config.shop_name,
                                               order.order_id,
                                               customer_name)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'shopowner_mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             shop_config=self.shop_config)
        self._send_mail(mail_to, mail_subject, msg_body, reply_to=customer_address)

    def _send_customer_mail(self, order, lang):
        """Send order confirmation mail to customer
        """
        show_prices = self.show_prices(order)
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        mail_to = formataddr((customer_name, order.customer_email))

        mail_subject = self.shop_config.mail_subject
        if not mail_subject:
            mail_subject = u'Your Webshop Order'
        mail_subject = translate(mail_subject, domain='ftw.shop',
                                 context=self.request, default=mail_subject)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             shop_config=self.shop_config)
        self._send_mail(mail_to, mail_subject, msg_body)

    def _send_supplier_mail(self, supplier, order):
        """Send order notification to a (single) supplier.
        """
        show_prices = self.show_prices(order)
        mail_to = formataddr(supplier)
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        customer_address = formataddr((customer_name, order.customer_email))
        mail_subject = '[%s] Order %s by %s' % (self.shop_config.shop_name,
                                               order.order_id,
                                               customer_name)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'supplier_mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             shop_config=self.shop_config,
                             supplier=supplier)
        self._send_mail(mail_to, mail_subject, msg_body, reply_to=customer_address)

    def _send_mail(self, to, subject, body, reply_to=None):
        """Send mail originating from the shop.
        """

        mail_bcc = getattr(self.shop_config, 'mail_bcc', '')
        mail_from = formataddr((self.shop_config.shop_name,
                               self.shop_config.shop_email))
        self.mhost.send(body,
             mto=to,
             mfrom=mail_from,
             mbcc=mail_bcc,
             reply_to=reply_to,
             subject=subject,
             encode=None,
             immediate=False,
             msg_type='text/html',
             charset='latin1')

    def show_prices(self, order):
        for item in order.cartitems:
            if item.show_price:
                return True
        return False

    def showStatus(self):
        registry = getUtility(IRegistry)
        shop_config = registry.forInterface(IShopConfiguration)
        return shop_config.show_status_column

    def getStatusSet(self):
        """Return the vocabulary for the currently
        selected StatusSet
        """
        status_set_name = self.shop_config.status_set
        status_set = getAdapter((self.context,), name=status_set_name)
        return status_set.vocabulary
Example #4
0
class OrderManagerView(BrowserView):
    """Lists orders stored in a IOrderStorage
    """

    template = ViewPageTemplateFile('templates/order_manager.pt')
    change_status_tmpl = ViewPageTemplateFile('templates/status.pt')

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.request.set('disable_border', True)
        registry = getUtility(IRegistry)
        self.shop_config = registry.forInterface(IShopConfiguration)
        self.mhost = IMailHostAdapter(self.context)
        self.order_storage = getUtility(IOrderStorage,
                                        name=self.shop_config.order_storage)
        self.supplier_filter = None
        self.status_filter = None
        super(OrderManagerView, self).__init__(context, request)


    def __call__(self):
        from_date, to_date = self.parse_date_range()
        self.supplier_filter = self.request.form.get('supplier',
            'all_suppliers')
        self.status_filter = self.request.form.get('form.widgets.status_filter', 'all')
        self.order_results = self.getOrders(from_date, to_date)
        if self.request.form.get('filter'):
            return self.__of__(self.context).template()
        elif self.request.form.get('download_csv'):
            return self.download_csv()
        elif self.request.form.get('cancel_orders'):
            return self.cancel_orders()
        elif self.request.form.get('change_status_step1'):
            return self.__of__(self.context).change_status_tmpl()
        elif self.request.form.get('change_status'):
            return self.change_status()
        else:
            return self.__of__(self.context).template()


    def parse_date_range(self):
        """Parse the from_date and to_date strings,
        assuming the jQuery UI datepicker widget always
        stores them in the request in the "%d.%m.%Y"
        format.
        """

        try:
            from_date = strptime(self.request.form.get(
                'from_date', ''), "%d.%m.%Y").date()
        except ValueError:
            from_date = date(2001, 1, 1)
        try:
            to_date = strptime(self.request.form.get(
                'to_date', ''), "%d.%m.%Y").date()
        except ValueError:
            to_date = date(2100, 1, 1)
        return (from_date, to_date)


    def getSuppliers(self):
        catalog = getToolByName(self.context, 'portal_catalog')
        brains = catalog(portal_type="Supplier")
        results = [dict(name=b.Title, email=b.email) for b in brains]
        return results

    def download_csv(self):
        """Returns a CSV file containing the shop orders
        """

        filename = "orders.csv"
        stream = cStringIO.StringIO()
        csv_writer = csv.writer(stream, dialect='excel', delimiter=';',
                                quotechar='"', quoting=csv.QUOTE_MINIMAL)
        core_cols = ['order_id',
                      'title',
                      'status',
                      'total',
                      'date',
                      'customer_title',
                      'customer_firstname',
                      'customer_lastname',
                      'customer_company',
                      'customer_email',
                      'customer_street1',
                      'customer_street2',
                      'customer_phone',
                      'customer_zipcode',
                      'customer_city',
                      'customer_shipping_address',
                      'customer_country',
                      'customer_comments']

        # Create union of core_cols + all_cols to retain order
        all_cols = self.order_storage.getFieldNames()
        columns = core_cols + filter(lambda x:x not in core_cols, all_cols)
        cart_cols = ['sku_code', 'quantity', 'dimensions', 'title', 'price',
                     'item_total', 'supplier_name', 'supplier_email']

        column_titles = [COLUMN_TITLES[col].decode('utf-8').encode('cp1252') for col in columns + cart_cols]
        # Write header row
        csv_writer.writerow(column_titles)

        for order in self.order_results:
            order_data = [getattr(order, attr, '') for attr in columns]

            # Get the total via getTotal accessor to convert it to Decimal
            order_data[columns.index('total')] = order.getTotal()

            for i, value in enumerate(order_data):
                if isinstance(value, unicode):
                    order_data[i] = value.encode('cp1252')

            for cart_item in order.cartitems:
                # format dimensions
                dimensions = [(cart_item.dimensions[i], dim) for i, dim in enumerate(cart_item.selectable_dimensions)]
                dim_strings = [' '.join([str(dim[0]), translate(_(dim[1]), context=self.request)]) for dim in dimensions]
                dim_formatted = ','.join(dim_strings)

                cart_data = [cart_item.sku_code,
                            cart_item.quantity,
                            dim_formatted,
                            cart_item.title,
                            cart_item.getPrice(),
                            cart_item.getTotal(),
                            cart_item.supplier_name,
                            cart_item.supplier_email]

                for i, value in enumerate(cart_data):
                    if isinstance(value, unicode):
                        cart_data[i] = value.encode('cp1252')

                csv_writer.writerow(order_data + cart_data)

        RESPONSE = self.request.RESPONSE
        header_value = contentDispositionHeader('attachment',
                                                'cp1252',
                                                filename=filename)
        if not DEBUG:
            RESPONSE.setHeader("Content-Disposition", header_value)
            RESPONSE.setHeader("Content-Type",
                           'text/comma-separated-values;charset=%s' % 'cp1252')
        else:
            RESPONSE.setHeader("Content-Type",
                           'text/plain; charset=%s' % 'cp1252')

        stream.seek(0)
        return stream.read()

    def cancel_orders(self):
        """Cancel orders by their order_ids
        """
        context = aq_inner(self.context)
        ptool = getToolByName(context, 'plone_utils')
        order_storage = self.getOrderStorage()

        orders = self.request.form.get('orders', [])
        for order_id in orders:
            try:
                order_id = int(order_id)
            except ValueError:
                # Invalid order_id - continue with next one
                continue
            order_storage.cancelOrder(order_id)
        msg = _(u'msg_order_cancelled',
                default=u"${no_orders} orders cancelled.",
                mapping={ u"no_orders" : len(orders)})
        ptool.addPortalMessage(msg, 'info')
        self.request.response.redirect("%s/order_manager" % context.absolute_url())

    def change_status(self):
        """Change status of several orders at once
        """
        context = aq_inner(self.context)
        ptool = getToolByName(context, 'plone_utils')
        order_storage = self.getOrderStorage()

        orders = self.request.form.get('orders', [])
        new_status = self.request.form.get('form.widgets.status', None)

        # Change status of the orders
        for order_id in orders:
            try:
                order_id = int(order_id)
            except ValueError:
                # Invalid order_id - continue with next one
                continue
            order = order_storage.getOrder(order_id)
            order.status = int(new_status)

        msg = _(u'msg_status_changed',
                default=u"Changed status for ${no_orders} orders.",
                mapping={ u"no_orders" : len(orders)})
        ptool.addPortalMessage(msg, 'info')
        return self.template()


    def getOrders(self, from_date=None, to_date=None):
        order_storage = self.order_storage
        all_orders = order_storage.getAllOrders()

        if any([from_date and to_date, self.supplier_filter, self.status_filter]):
            # Filter orders
            orders = []
            for order in all_orders:
                suppliers = [item.supplier_name for item in order.cartitems]
                if (self.supplier_filter in suppliers
                or self.supplier_filter in ["all_suppliers", "", None]) \
                and self.status_filter == str(order.status) \
                or self.status_filter == "all" \
                and from_date <= order.date.date() \
                and to_date >= order.date.date():
                    orders.append(order)
        else:
            orders = all_orders
        return orders

    def getOrder(self, order_id):
        order_storage = self.order_storage
        order = order_storage.getOrder(order_id)
        return order

    def getOrderStorage(self):
        return self.order_storage

    def addOrder(self):
        """Add a new Order and return the order id.
        """

        session = self.context.REQUEST.SESSION

        # check for cart
        cart_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'cart_view')
        cart_data = cart_view.cart_items()

        # check for customer data
        customer_data = session.get(SESSION_ADDRESS_KEY, {})
        if not customer_data:
            raise MissingCustomerInformation

        # check for shipping address
        shipping_data = session.get(SESSION_SHIPPING_KEY, {})
        if not shipping_data:
            raise MissingShippingAddress

        # check for review data
        review_data = session.get(SESSION_REVIEW_KEY, {})
        # The comment was previously in the customer data step. If we move it
        # to the customer data set we can avoid changing all templates.
        customer_data.update(review_data)

        # check for order confirmation
        if not session.get('order_confirmation', None):
            raise MissingOrderConfirmation

        # check for payment processor
        payment_processor_step_groups = getAdapters(
                                        (self.context, self.request, self),
                                        IPaymentProcessorStepGroup)

        selected_pp_step_group = self.shop_config.payment_processor_step_group
        for name, step_group_adapter in payment_processor_step_groups:
            if name == selected_pp_step_group:
                payment_processor_steps = step_group_adapter.steps

        if not len(payment_processor_steps) == 0 \
            and not session.get('payment_processor_choice', None):
            raise MissingPaymentProcessor

        # change security context to owner
        user = self.context.getWrappedOwner()
        newSecurityManager(self.context.REQUEST, user)

        order_storage = self.order_storage
        order_id = order_storage.createOrder(status=ONLINE_PENDING_KEY,
                                             date=datetime.now(),
                                             customer_data=customer_data,
                                             shipping_data=shipping_data,
                                             total=cart_view.cart_total(),
                                             cart_data=cart_data)
        order_storage.flush()

        noSecurityManager()

        return order_id

    def sendOrderMails(self, order_id):
        """Send order confirmation and notification mails for the order with
        the specified order_id.
        """

        order = self.order_storage.getOrder(order_id)

        ltool = getToolByName(self.context, 'portal_languages')
        lang = ltool.getPreferredLanguage()

        # Send order confirmation to customer
        self._send_customer_mail(order, lang)

        # Send order notification to supplier(s)
        suppliers = []
        for item_type in order.cartitems:
            if not (item_type.supplier_name == '' \
                or item_type.supplier_email == ''):
                for email_address in item_type.supplier_email.split(','):
                    suppliers.append((item_type.supplier_name,
                                      email_address.strip()))
        unique_suppliers = set(suppliers)
        for supplier in unique_suppliers:
            self._send_supplier_mail(supplier, order)

        # Send order notification to shop owner
        if self.shop_config.always_notify_shop_owner:
            self._send_owner_mail(order)

        return

    def _send_owner_mail(self, order):
        """Send order notification to shop owner.
        """
        show_prices = self.show_prices(order)
        mail_to = formataddr(("Shop Owner", self.shop_config.shop_email))
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        customer_address = formataddr((customer_name, order.customer_email))
        mail_subject = '[%s] Order %s by %s' % (self.shop_config.shop_name,
                                               order.order_id,
                                               customer_name)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'shopowner_mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             has_order_dimensions=self.has_order_dimensions(order),
                             shop_config=self.shop_config)
        self._send_mail(mail_to, mail_subject, msg_body, reply_to=customer_address)

    def _send_customer_mail(self, order, lang):
        """Send order confirmation mail to customer
        """
        show_prices = self.show_prices(order)
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        mail_to = formataddr((customer_name, order.customer_email))

        mail_subject = self.shop_config.mail_subject
        if not mail_subject:
            mail_subject = u'Your Webshop Order'
        mail_subject = translate(mail_subject, domain='ftw.shop',
                                 context=self.request, default=mail_subject)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             has_order_dimensions=self.has_order_dimensions(order),
                             shop_config=self.shop_config)
        self._send_mail(mail_to, mail_subject, msg_body)

    def _send_supplier_mail(self, supplier, order):
        """Send order notification to a (single) supplier.
        """
        show_prices = self.show_prices(order)
        mail_to = formataddr(supplier)
        customer_name = "%s %s" % (order.customer_firstname,
                                   order.customer_lastname)
        customer_address = formataddr((customer_name, order.customer_email))
        mail_subject = '[%s] Order %s by %s' % (self.shop_config.shop_name,
                                               order.order_id,
                                               customer_name)

        mail_view = getMultiAdapter((self.context, self.context.REQUEST),
                                    name=u'supplier_mail_view')
        msg_body = mail_view(order=order,
                             show_prices=show_prices,
                             has_order_dimensions=self.has_order_dimensions(order),
                             shop_config=self.shop_config,
                             supplier=supplier)
        self._send_mail(mail_to, mail_subject, msg_body, reply_to=customer_address)

    def _send_mail(self, to, subject, body, reply_to=None):
        """Send mail originating from the shop.
        """

        mail_bcc = getattr(self.shop_config, 'mail_bcc', '')
        mail_from = formataddr((self.shop_config.shop_name,
                               self.shop_config.shop_email))
        self.mhost.send(body,
             mto=to,
             mfrom=mail_from,
             mbcc=mail_bcc,
             reply_to=reply_to,
             subject=subject,
             encode=None,
             immediate=False,
             msg_type='text/html',
             charset='latin1')

    def show_prices(self, order):
        for item in order.cartitems:
            if item.show_price:
                return True
        return False

    def has_order_dimensions(self, order):
        """Checks if order has an item with dimensions.
        """
        for item in order.cartitems:
            if len(item.dimensions) > 0:
                return True
        return False

    def showStatus(self):
        registry = getUtility(IRegistry)
        shop_config = registry.forInterface(IShopConfiguration)
        return shop_config.show_status_column

    def getStatusSet(self):
        """Return the vocabulary for the currently
        selected StatusSet
        """
        status_set_name = self.shop_config.status_set
        status_set = getAdapter((self.context,), name=status_set_name)
        return status_set.vocabulary