def __call__(self):
        self.request.set("disable_plone.leftcolumn", True)
        self.request.set("disable_plone.rightcolumn", True)

        if self.request.form.get("form.buttons.Export", None) is not None:
            out = StringIO()
            writer = csv.writer(out, delimiter="|", quoting=csv.QUOTE_MINIMAL)
            plone = self.context.restrictedTraverse("@@plone")
            encoding = plone.site_encoding()
            headers = [self.context.translate(_(header)).encode(encoding) for header in self.table_headers()]
            writer.writerow(headers)

            for article in self.articles():
                writer.writerow(
                    (
                        article["sku"].encode(encoding),
                        article["title"],
                        article["price"],
                        article["stock"],
                        article["subtotal"],
                    )
                )

            filename = "stock-{}.csv".format(datetime.now().isoformat())
            cd = 'attachment; filename="{}"'.format(filename)
            self.request.response.setHeader("Content-Type", "text/csv")
            self.request.response.setHeader("Content-Disposition", cd)
            return out.getvalue()

        return self.template()
 def __call__(self):
     if not self.shopping_site().is_addresses_filled():
         message = _(u"info_missing_from_addresses", default=u"Some information is missing from addresses.")
         IStatusMessage(self.request).addStatusMessage(message, type="info")
         url = "{}/@@billing-and-shipping".format(self.context.absolute_url())
         return self.request.response.redirect(url)
     if not super(OrderConfirmationView, self).__call__():
         return self.template()
    def update(self):
        super(CartArticleListingViewlet, self).update()
        form = self.request.form
        uuid = form.get('form.buttons.UpdateArticle')

        if uuid is not None:

            authenticator = self.context.restrictedTraverse('@@authenticator')
            if not authenticator.verify():
                raise Forbidden()

            quantity = form.get(uuid)
            validate = validation.validatorFor('isInt')

            if quantity is not None and validate(quantity) == 1 and int(quantity) >= 0:
                quantity = int(quantity)
                shopping_site = self.view.shopping_site()
                carticle = shopping_site.get_cart_article(uuid)
                adapter = getMultiAdapter((self.context, carticle), ICartArticleMultiAdapter)
                article = adapter.orig_article()
                if quantity == 0:
                    shopping_site.remove_cart_articles(uuid)
                elif article:
                    stock = IStock(article).stock()
                    reducible_quantity = IStock(article).reducible_quantity

                    if stock > reducible_quantity:
                        stock = reducible_quantity

                    if quantity > stock:
                        quantity = stock
                        message = _(u'no_more_than_quantity',
                            default=u"No more than ${quantity} can be added to cart for ${title}",
                            mapping={'quantity': quantity, 'title': safe_unicode(carticle['title'])})
                        IStatusMessage(self.request).addStatusMessage(message, type='info')

                    if quantity != carticle['quantity']:
                        carticle['quantity'] = quantity

            else:
                message = _(u"Invalid quantity.")
                IStatusMessage(self.request).addStatusMessage(message, type='warn')

            url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()
            return self.request.response.redirect(url)
 def buttons(self):
     buttons = super(CartCheckOutButtonsViewlet, self).buttons()[1:]
     buttons.insert(0, {
         'class': 'clear',
         'formnovalidate': True,
         'name': 'form.buttons.ClearCart',
         'title': _(u'Clear'),
         'value': 'form.buttons.ClearCart',
     })
     return buttons
def warn_number_of_images(context, event):
    if context == event.object:
        container = aq_chain(aq_inner(context))[3]
        if IArticle.providedBy(container):
            number_of_images = getUtility(IRegistry)['collective.cart.shopping.number_of_images']
            if len(IAdapter(container).get_brains(IATImage, depth=1)) >= number_of_images:
                message = _(u"You need to first remove some images to add here one.")
                IStatusMessage(container.REQUEST).addStatusMessage(message, type='warn')
                url = '{}/@@folder_contents'.format(container.absolute_url())
                return container.REQUEST.RESPONSE.redirect(url)
 def update(self):
     form = self.request.form
     oid = form.get('form.buttons.Remove')
     if oid is not None:
         stock = self.context[oid].stock
         url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()
         ids = [oid]
         self.context.manage_delObjects(ids)
         message = _(u'successfully_removed_stock', default=u'Successfully removed ${number} pc(s) of stock.', mapping={
             'number': stock})
         IStatusMessage(self.request).addStatusMessage(message, type='info')
         return self.request.response.redirect(url)
    def buttons(self):
        """Returns list of dictionary of buttons

        :rtype: list
        """
        return [
            {
                'class': 'back',
                'formnovalidate': True,
                'name': 'form.buttons.Back',
                'title': _(u'Back'),
                'value': 'form.buttons.Back',
            },
            {
                'class': 'next',
                'formnovalidate': False,
                'name': 'form.buttons.CheckOut',
                'title': _(u'Next'),
                'value': 'form.buttons.CheckOut',
            }
        ]
    def update(self):
        url = super(OrderConfirmationCheckOutButtonsViewlet, self).update()

        form = self.request.form
        if form.get('form.buttons.CheckOut') is not None:

            if self.view.shopping_site().get_brain_for_text('terms-message') and form.get('accept-terms') is None:
                message = _(u'need_to_accept_terms', default=u"You need to accept the terms to process the order.")
                IStatusMessage(self.request).addStatusMessage(message, type='info')
                url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()

            return self.request.response.redirect(url)
    def update_address(self, name, data):
        """Update address of cart and return message if there are one

        :param name: Name of address, such as billing and shipping.
        :type name: str

        :param data: Form data.
        :type data: dict

        :rtype: unicode or None
        """
        message = None

        items = data
        data = {}
        for key in items:
            text = '{}_'.format(name)
            if key.startswith(text):
                data[key[len(text):]] = items.get(key)

        if not data.get('first_name'):
            message = _(u'First name is missing.')

        elif not data.get('last_name'):
            message = _(u'Last name is missing.')

        elif not data.get('email') or validation.validatorFor('isEmail')(data.get('email')) != 1:
            message = _(u'Invalid e-mail address.')

        elif not data.get('street'):
            message = _(u'Street address is missing.')

        elif not data.get('post'):
            message = _(u'Post code is missing.')

        elif not data.get('city'):
            message = _(u'City is missing.')

        elif not data.get('phone'):
            message = _(u'Phone number is missing.')

        else:
            address = self.get_address(name)
            if address is not None:
                for key in data:
                    value = data.get(key)
                    if address.get(key) != value:
                        address[key] = value
            else:
                address = data
            self.update_cart(name, address)

        return message
    def update(self):
        form = self.request.form
        url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()
        stock = IStock(self.context)

        if form.get('form.buttons.QuickAdd') is not None:
            value = form.get('quick-add')
            validate = validation.validatorFor('isInt')
            maximum = self.add()['max']
            if validate(value) != 1:
                message = _(u'add_less_than_number', default=u'Add less than ${number}.', mapping={'number': maximum})
                IStatusMessage(self.request).addStatusMessage(message, type='warn')
            else:
                value = int(value)
                message = _(u'successfully_added_number', default=u'Successfully added ${number} pc(s).', mapping={
                    'number': stock.add_stock(value)})
                IStatusMessage(self.request).addStatusMessage(message, type='info')
            return self.request.response.redirect(url)

        elif form.get('form.buttons.QuickSubtract') is not None:
            value = form.get('quick-subtract')
            validate = validation.validatorFor('isInt')
            maximum = self.subtract()['max']
            if validate(value) != 1:
                message = _(u'subtract_less_than_number', default=u'Subtract less than ${number}.', mapping={'number': maximum})
                IStatusMessage(self.request).addStatusMessage(message, type='warn')
            else:
                value = int(value)
                message = _(u'successfully_subtracted_number', default=u'Successfully subtracted ${number} pc(s).', mapping={
                    'number': stock.sub_stock(value)})
                IStatusMessage(self.request).addStatusMessage(message, type='info')
            return self.request.response.redirect(url)

        elif form.get('form.buttons.AddNewStock') is not None:
            url = '{}/++add++collective.cart.stock.Stock'.format(self.context.absolute_url())
            return self.request.response.redirect(url)
    def update(self):
        url = super(BillingAndShippingCheckOutButtonsViewlet, self).update()

        form = self.request.form

        if form.get('form.buttons.CheckOut') is not None:

            current_url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()
            shopping_site = self.view.shopping_site()
            message = shopping_site.update_address('billing', form)
            if message is not None:
                IStatusMessage(self.request).addStatusMessage(message, type='warn')
                url = current_url

            notify(BillingAddressConfirmedEvent(self.context))

            if form.get('billing-same-as-shipping', 'different') == 'same':
                shopping_site.update_cart('billing_same_as_shipping', True)
            else:
                shopping_site.update_cart('billing_same_as_shipping', False)

                message = shopping_site.update_address('shipping', form)
                if message is not None:
                    IStatusMessage(self.request).addStatusMessage(message, type='warn')
                    url = current_url

                notify(ShippingAddressConfirmedEvent(self.context))

            shipping_method = form.get('shipping-method')
            if not self.single_shipping_method() and not shipping_method:
                message = _(u'Select one shipping method.')
                IStatusMessage(self.request).addStatusMessage(message, type='warn')
                url = current_url

            else:
                shopping_site.update_shipping_method(shipping_method)

            return self.request.response.redirect(url)
def notify_ordered(context, event):
    if event.action == 'ordered':
        shopping_site = IShoppingSite(context)
        adapter = IOrderAdapter(context)
        portal = shopping_site.portal()
        email_from_address = getUtility(IRegistry)['collective.cart.shopping.notification_cc_email'] or portal.getProperty('email_from_address')

        billing = shopping_site.get_address('billing')
        default_charset = getattr(getattr(getToolByName(context, 'portal_properties'), 'site_properties'), 'default_charset', 'utf-8')
        email_charset = getUtility(ISiteRoot).getProperty('email_charset', 'utf-8')
        subject = context.translate(_(u'order-number', u'Order Number: ${number}', mapping={'number': context.id}))
        utility = getUtility(IUnicodeUtility)
        mfrom = u'"{}" <{}>'.format(utility.safe_unicode(shopping_site.shop().title), email_from_address)
        host = getToolByName(context, 'MailHost')

        underline = '=' * 28
        billing_address = utility.address(billing)
        if shopping_site.billing_same_as_shipping():
            shipping_address = billing_address
        else:
            shipping = shopping_site.get_address('shipping')
            shipping_address = utility.address(shipping)
        articles = shopping_site.cart_article_listing()
        for article in articles:
            subtotal = article['gross'] * article['quantity']
            article.update({'subtotal': shopping_site.format_money(subtotal)})
        shipping_method_title = hasattr(
            adapter.shipping_method(), 'Title') and adapter.shipping_method().Title.decode(default_charset) or u''

        items = shopping_site.cart().copy()
        for key in ['articles', 'billing_same_as_shipping', 'shipping_method', 'billing', 'shipping']:
            if key in items:
                del items[key]

        items.update({
            'number': context.id,
            'underline': underline,
            'billing_address': billing_address,
            'shipping_address': shipping_address,
            'articles': articles,
            'shipping_method_title': shipping_method_title,
            'is_shipping_free': shopping_site.shipping_gross_money().amount == 0.0,
            'shipping_gross': shopping_site.locale_shipping_gross(),
            'total': shopping_site.locale_total(),
        })

        message_to_customer = context.unrestrictedTraverse('@@to-customer-order-mail-template')(**items)
        mto_customer = u'"{}" <{}>'.format(utility.fullname(billing), billing['email'])
        subject_to_customer = subject

        message_to_shop = context.unrestrictedTraverse('@@to-shop-order-mail-template')(**items)
        mto_shop = mfrom
        subject_to_shop = subject

        try:
            host.send(message_to_customer, mto_customer, mfrom, subject=subject_to_customer, charset=email_charset)
            host.send(message_to_shop, mto_shop, mfrom, subject=subject_to_shop, charset=email_charset)

        except:
            message = _(u'order-processed-but',
                default=u'The order was processed but we could not send e-mail to you successfully. Please consult the shop owner.')
            IStatusMessage(context.REQUEST).addStatusMessage(message, type='warn')
    def table_headers(self):
        """Returns headers for table

        :rtype: tuple
        """
        return (_(u"SKU"), _(u"Name"), _(u"Price"), _(u"Stock"), _(u"Subtotal"))
 def title(self):
     """Returns title"""
     title = safe_unicode(super(StockView, self).title())
     return _(u"stock_of_article", u"${title}: ${stock} pcs", mapping={"title": title, "stock": self.stock()})
 def description(self):
     if not self.stocks():
         return _(u"description_no_stocks_available", u"There are no stocks available.")
def add_status_message_article_added(event):
    article = event.article
    message = _(u"article-added-to-cart", default=u"${title} is added to cart.", mapping={'title': safe_unicode(article.title())})
    IStatusMessage(event.request).addStatusMessage(message, type='info')
class OrderSchema(BaseOrderSchema):
    """Schema for content type: collective.cart.core.Order"""

    billing_same_as_shipping = schema.Bool(
        title=_(u'Billing info same as shipping info'),
        required=False,
        default=True)


class OrderArticleSchema(BaseOrderArticleSchema):
    """Schema for content type: collective.cart.core.OrderArticle"""


info_types = SimpleVocabulary([
    SimpleTerm(value=u'billing', title=_(u'Billing')), SimpleTerm(value=u'shipping', title=_(u'Shipping'))])


class CustomerInfoSchema(Schema):
    """Schema for content type: collective.cart.shopping.CustomerInfo"""

    first_name = schema.TextLine(
        title=_(u'First Name'))

    last_name = schema.TextLine(
        title=_(u'Last Name'))

    organization = schema.TextLine(
        title=_(u'Organization'),
        required=False)
    def add_to_cart(self):
        """Add article to cart"""
        shopping_site = IShoppingSite(self.context)
        form = self.request.form
        add_to_cart = form.pop('form.buttons.AddToCart', None)
        subarticle = form.pop('subarticle', None)

        uuid = None
        quantity = '1'

        if subarticle is not None:

            uuids = subarticle
            parent_uuid = add_to_cart

            if not isinstance(uuids, list):
                uuids = [subarticle]

            for subarticle_uuid in uuids:
                parent = aq_parent(aq_inner(shopping_site.get_object(UID=subarticle_uuid)))
                if parent_uuid == IUUID(parent):
                    uuid = subarticle_uuid

                quantity = form.get(parent_uuid)

        uuid = uuid or add_to_cart

        if uuid is not None:

            quantity = form.get('quantity') or form.get(uuid) or quantity
            validate = validation.validatorFor('isInt')
            url = self.context.restrictedTraverse('@@plone_context_state').current_base_url()
            message = None

            if quantity is not None and validate(quantity) == 1:
                quantity = int(quantity)
                obj = shopping_site.get_object(UID=uuid)
                if obj:
                    item = IArticleAdapter(obj)
                    if quantity > item.quantity_max():
                        quantity = item.quantity_max()
                    if quantity > 0:
                        size = ISize(obj)
                        gross = item.gross()
                        kwargs = {
                            'depth': size.depth,
                            'gross': gross,
                            'height': size.height,
                            'net': item.get_net(gross),
                            'quantity': quantity,
                            'title': item.title(),
                            'sku': obj.sku,
                            'vat': item.get_vat(gross),
                            'vat_rate': item.context.vat_rate,
                            'weight': size.weight,
                            'width': size.width,
                        }
                        item.add_to_cart(**kwargs)
                        notify(ArticleAddedToCartEvent(item, self.request))
                    else:
                        message = _(u'Input positive integer value to add to cart.')
                else:
                    message = _(u"Not available to add to cart.")
            else:
                message = _(u"Input integer value to add to cart.")

            if message:
                IStatusMessage(self.request).addStatusMessage(message, type='warn')

            return self.request.response.redirect(url)