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)