def listing(self): # XXX: discount ret = list() for booking in self.order_data.bookings: obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) state = vocabs.state_vocab()[booking.attrs.get('state')] salaried = vocabs.salaried_vocab()[booking.attrs.get('salaried')] ret.append({ 'uid': booking.attrs['uid'], 'title': booking.attrs['title'], 'url': obj.absolute_url(), 'count': booking.attrs['buyable_count'], 'net': ascur(booking.attrs.get('net', 0.0)), 'discount_net': ascur(float(booking.attrs['discount_net'])), 'vat': booking.attrs.get('vat', 0.0), 'comment': booking.attrs['buyable_comment'], 'quantity_unit': booking.attrs.get('quantity_unit'), 'currency': booking.attrs.get('currency'), 'state': state, 'salaried': salaried, }) return ret
def listing(self): # XXX: discount can_cancel_booking = self.can_cancel_booking ret = list() for booking in self.order_data.bookings: obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) state = vocabs.state_vocab()[booking.attrs.get('state')] salaried = vocabs.salaried_vocab()[booking.attrs.get('salaried')] cancel_target = None if can_cancel_booking and state != ifaces.STATE_CANCELLED: cancel_target = addTokenToUrl('{}?uid={}'.format( self.context.absolute_url(), booking.attrs['uid']) ) ret.append({ 'uid': booking.attrs['uid'], 'title': booking.attrs['title'], 'url': obj.absolute_url() if obj else None, 'cancel_target': cancel_target, 'count': booking.attrs['buyable_count'], 'net': ascur(booking.attrs.get('net', 0.0)), 'discount_net': ascur(float(booking.attrs['discount_net'])), 'vat': booking.attrs.get('vat', 0.0), 'comment': booking.attrs['buyable_comment'], 'quantity_unit': booking.attrs.get('quantity_unit'), 'currency': booking.attrs.get('currency'), 'state': state, 'salaried': salaried, }) return ret
def listing(self): # XXX: discount ret = list() for booking in self.order_data.bookings: obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) state = vocabs.state_vocab()[booking.attrs.get('state')] salaried = vocabs.salaried_vocab()[booking.attrs.get('salaried')] ret.append({ 'uid': booking.attrs['uid'], 'title': booking.attrs['title'], 'url': obj.absolute_url(), 'reserved': reserved( booking.attrs['remaining_stock_available'], booking.attrs['buyable_count']), 'count': booking.attrs['buyable_count'], 'net': ascur(booking.attrs.get('net', 0.0)), 'discount_net': ascur(float(booking.attrs['discount_net'])), 'vat': booking.attrs.get('vat', 0.0), 'comment': booking.attrs['buyable_comment'], 'quantity_unit': booking.attrs.get('quantity_unit'), 'currency': booking.attrs.get('currency'), 'state': state, 'salaried': salaried, }) return ret
def fix_bookings_vendor_uid(ctx=None): """Add vendor_uid attribute to booking records. """ portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for item in data.values(): update = False try: item.attrs['vendor_uid'] if not isinstance(item.attrs['vendor_uid'], uuid.UUID): update = True except KeyError: update = True if not update: continue buyable_uid = item.attrs['buyable_uid'] obj = get_object_by_uid(portal, buyable_uid) if not obj: shop = acquire_vendor_or_shop_root(portal) else: shop = acquire_vendor_or_shop_root(obj) vendor_uid = uuid.UUID(IUUID(shop)) item.attrs['vendor_uid'] = vendor_uid need_rebuild = True logging.info( u"Added vendor_uid to booking {0}".format(item.attrs['uid']) ) if need_rebuild: soup.rebuild() logging.info("Rebuilt bookings catalog")
def fix_bookings_trading(ctx=None): portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for booking in data.values(): try: booking.attrs['item_number'] except KeyError: obj = get_object_by_uid(portal, booking.attrs['buyable_uid']) if obj: trading = ITrading(obj) item_number = trading.item_number gtin = trading.gtin else: item_number = '' gtin = '' need_rebuild = True booking.attrs['item_number'] = item_number logging.info( u"Added item_number {0} to booking {1}".format( item_number, booking.attrs['uid'] ) ) booking.attrs['gtin'] = gtin logging.info( u"Added gtin {0} to booking {1}".format( gtin, booking.attrs['uid'] ) ) if need_rebuild: bookings_soup = get_bookings_soup(portal) bookings_soup.rebuild() logging.info("Rebuilt bookings catalog")
def fix_bookings_vendor_uid(ctx=None): """Add vendor_uid attribute to booking records. """ portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for item in data.values(): update = False try: item.attrs['vendor_uid'] if not isinstance(item.attrs['vendor_uid'], uuid.UUID): update = True except KeyError: update = True if not update: continue buyable_uid = item.attrs['buyable_uid'] obj = get_object_by_uid(portal, buyable_uid) if not obj: shop = acquire_vendor_or_shop_root(portal) else: shop = acquire_vendor_or_shop_root(obj) vendor_uid = uuid.UUID(IUUID(shop)) item.attrs['vendor_uid'] = vendor_uid need_rebuild = True logging.info("Added vendor_uid to booking {0}".format( item.attrs['uid'])) if need_rebuild: soup.rebuild() logging.info("Rebuilt bookings catalog")
def fix_bookings_trading(ctx=None): portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for booking in data.values(): try: booking.attrs['item_number'] except KeyError: obj = get_object_by_uid(portal, booking.attrs['buyable_uid']) if obj: trading = ITrading(obj) item_number = trading.item_number gtin = trading.gtin else: item_number = '' gtin = '' need_rebuild = True booking.attrs['item_number'] = item_number logging.info("Added item_number {0} to booking {1}".format( item_number, booking.attrs['uid'])) booking.attrs['gtin'] = gtin logging.info("Added gtin {0} to booking {1}".format( gtin, booking.attrs['uid'])) if need_rebuild: bookings_soup = get_bookings_soup(portal) bookings_soup.rebuild() logging.info("Rebuilt bookings catalog")
def buyable_available(context, booking): obj = get_object_by_uid(context, booking.attrs['buyable_uid']) if not obj: return None item_stock = get_item_stock(obj) if not item_stock: return None return item_stock.available
def event_url(context, booking): """Function for COMPUTED_BOOKING_EXPORT_ATTRS to return a url for a given context object and booking record. """ obj = get_object_by_uid(context, booking.attrs['buyable_uid']) if obj: return _get_event_url(obj) return None
def event_url(context, booking): """Function for COMPUTED_BOOKING_EXPORT_ATTRS to return a url for a given context object and booking record. """ obj = get_object_by_uid(context, booking.attrs["buyable_uid"]) if obj: return _get_event_url(obj) return None
def increase_stock(self, booking): obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) # object no longer exists if not obj: return stock = get_item_stock(obj) # if stock.available is None, no stock information used if stock.available is not None: stock.available += float(booking.attrs['buyable_count'])
def decrease_stock(self, booking): obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) # object no longer exists if not obj: return stock = get_item_stock(obj) # if stock.available is None, no stock information used if stock.available is not None: # TODO: ATTENTION: here might get removed more than available..? stock.available -= float(booking.attrs['buyable_count'])
def decrease_stock(self, bookings): for booking in bookings: obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) # object no longer exists if not obj: continue stock = get_item_stock(obj) # if stock.available is None, no stock information used if stock.available is not None: stock.available -= float(booking.attrs['buyable_count'])
def product_group(self): uid = self.request.get('uid') if not uid: raise ValueError(u'No execution context UID') obj = get_object_by_uid(self.context, uid) if not obj: raise ValueError(u'Execution context object not found by UID') if IProductGroup.providedBy(obj): return obj if IVariant.providedBy(obj): return aq_parent(obj) raise ValueError(u'Object not implements IProductGroup or IVariant')
def listing(self): ret = list() for booking in self.order_data.bookings: obj = get_object_by_uid(self.context, booking.attrs['buyable_uid']) ret.append({ 'uid': booking.attrs['uid'], 'title': booking.attrs['title'], 'url': obj.absolute_url(), 'count': booking.attrs['buyable_count'], 'quantity_unit': booking.attrs.get('quantity_unit'), }) return ret
def validate_count(self, uid, count): """Validate setting cart item count for uid. uid - Is the cart item UID. count - If count is 0, it means that a cart item is going to be deleted, which is always allowed. If count is > 0, it's the aggregated item count in cart. """ count = float(count) # count is 0, return if not count: return {'success': True, 'error': ''} cart_item = get_object_by_uid(self.context, uid) item_data = get_item_data_provider(cart_item) buyable_event = self.acquire_event(cart_item) buyable_event_data = IBuyableEventData(buyable_event) # cart count limit is set for all event tickets if buyable_event_data.cart_count_limit: related_uids = IEventTickets(cart_item).related_uids aggregated_count = count items = extractitems(readcookie(self.request)) for ticket_uid in related_uids: # we already have count for item to validate if uid == ticket_uid: continue aggregated_count += float( aggregate_cart_item_count(ticket_uid, items)) if aggregated_count > buyable_event_data.cart_count_limit: message = translate( _('event_tickets_limit_reached', default="Limit of tickets for this event reached"), context=self.request) return {'success': False, 'error': message} # cart count limit is set for ticket elif item_data.cart_count_limit: if count > item_data.cart_count_limit: message = translate( _('ticket_limit_reached', default="Limit for this ticket reached"), context=self.request) return {'success': False, 'error': message} # stock check item_state = get_item_state(cart_item, self.request) if item_state.validate_count(count): return {'success': True, 'error': ''} # out of stock message = translate(_('trying_to_add_more_tickets_than_available', default="Not enough tickets available, abort."), context=self.request) return {'success': False, 'error': message}
def validate_count(self, uid, count): """Validate setting cart item count for uid. uid - Is the cart item UID. count - If count is 0, it means that a cart item is going to be deleted, which is always allowed. If count is > 0, it's the aggregated item count in cart. """ count = float(count) # count is 0, return if not count: return {'success': True, 'error': ''} cart_item = get_object_by_uid(self.context, uid) item_data = get_item_data_provider(cart_item) buyable_event = self.acquire_event(cart_item) buyable_event_data = IBuyableEventData(buyable_event) # cart count limit is set for all event tickets if buyable_event_data.cart_count_limit: related_uids = IEventTickets(cart_item).related_uids aggregated_count = count items = extractitems(readcookie(self.request)) for ticket_uid in related_uids: # we already have count for item to validate if uid == ticket_uid: continue aggregated_count += float( aggregate_cart_item_count(ticket_uid, items)) if aggregated_count > buyable_event_data.cart_count_limit: message = translate(_( 'event_tickets_limit_reached', default="Limit of tickets for this event reached"), context=self.request) return {'success': False, 'error': message} # cart count limit is set for ticket elif item_data.cart_count_limit: if count > item_data.cart_count_limit: message = translate(_('ticket_limit_reached', default="Limit for this ticket reached"), context=self.request) return {'success': False, 'error': message} # stock check item_state = get_item_state(cart_item, self.request) if item_state.validate_count(count): return {'success': True, 'error': ''} # out of stock message = translate(_('trying_to_add_more_tickets_than_available', default="Not enough tickets available, abort."), context=self.request) return {'success': False, 'error': message}
def get_vendor_by_uid(context, vendor_uid): """Return vendor object by uid or site root as fallback if requested vendor not exists. :param vendor_uid: Vendor uid. :type vendor_uid: string or uuid.UUID object :returns: Vendor Object :rtype: IVendor implementing content Object """ if not isinstance(vendor_uid, uuid.UUID): vendor_uid = uuid.UUID(vendor_uid) vendor = get_object_by_uid(context, vendor_uid) if vendor is None: vendor = plone.api.portal.get() return vendor
def validate_set(self, uid): buyable = get_object_by_uid(self.context, uid) # check whether user can buy item sm = getSecurityManager() if not sm.checkPermission(permissions.BuyItems, buyable): remove_item_from_cart(self.request, uid) message = _(u'permission_not_granted_to_buy_item', default=u'Permission to buy ${title} not granted.', mapping={'title': buyable.Title()}) message = translate(message, context=self.request) return { 'success': False, 'error': message, 'update': True, } # check buyable period buyable_period = queryAdapter(buyable, IBuyablePeriod) if buyable_period: now = datetime.now() # effective date not reached yet effective = buyable_period.effective if effective and now < effective: remove_item_from_cart(self.request, uid) message = _('item_not_buyable_yet', default=u'Item not buyable yet') message = translate(message, context=self.request) return { 'success': False, 'error': message, 'update': True, } # expires date exceed expires = buyable_period.expires if expires and now > expires: remove_item_from_cart(self.request, uid) message = _('item_no_longer_buyable', default=u'Item no longer buyable') message = translate(message, context=self.request) return { 'success': False, 'error': message, 'update': True, } return { 'success': True, 'error': '', }
def fix_bookings_shippable(ctx=None): portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for booking in data.values(): try: booking.attrs['shippable'] except KeyError: obj = get_object_by_uid(portal, booking.attrs['buyable_uid']) shippable = True if obj: shippable = IShippingItem(obj).shippable booking.attrs['shippable'] = shippable need_rebuild = True logging.info("Added shippable {0} to booking {1}".format( shippable, booking.attrs['uid'])) if need_rebuild: bookings_soup = get_bookings_soup(portal) bookings_soup.rebuild() logging.info("Rebuilt bookings catalog")
def fix_bookings_shippable(ctx=None): portal = getSite() soup = get_bookings_soup(portal) data = soup.storage.data need_rebuild = False for booking in data.values(): try: booking.attrs['shippable'] except KeyError: obj = get_object_by_uid(portal, booking.attrs['buyable_uid']) shippable = True if obj: shippable = IShippingItem(obj).shippable booking.attrs['shippable'] = shippable need_rebuild = True logging.info( u"Added shippable {0} to booking {1}".format( shippable, booking.attrs['uid'] ) ) if need_rebuild: bookings_soup = get_bookings_soup(portal) bookings_soup.rebuild() logging.info("Rebuilt bookings catalog")
def buyable_overbook(context, booking): obj = get_object_by_uid(context, booking.attrs['buyable_uid']) if obj: item_stock = get_item_stock(obj) return item_stock.overbook return None
def test_get_object_by_uid(self): from bda.plone.cart import get_object_by_uid self.assertEquals(get_object_by_uid(self.portal, "foo"), None) obj = get_object_by_uid(self.portal, IUUID(self.doc)) self.assertEquals(obj, self.doc)
def test_get_object_by_uid(self): from bda.plone.cart import get_object_by_uid self.assertEquals(get_object_by_uid(self.portal, 'foo'), None) obj = get_object_by_uid(self.portal, IUUID(self.doc)) self.assertEquals(obj, self.doc)
def save(self, providers, widget, data): super(OrderCheckoutAdapter, self).save(providers, widget, data) order = self.order # order UUID uid = order.attrs['uid'] = uuid.uuid4() # order creator creator = None member = plone.api.user.get_current() if member: creator = member.getId() order.attrs['creator'] = creator # order creation date created = datetime.datetime.now() order.attrs['created'] = created cart_data = get_data_provider(self.context, self.request) # payment related information if cart_data.total > Decimal(0): payment_param = 'checkout.payment_selection.payment' pid = data.fetch(payment_param).extracted payment = Payments(self.context).get(pid) order.attrs['payment_method'] = pid if payment: order.attrs['payment_label'] = payment.label else: order.attrs['payment_label'] = _('unknown', default=u'Unknown') # no payment else: order.attrs['payment_method'] = 'no_payment' order.attrs['payment_label'] = _('no_payment', default=u'No Payment') # shipping related information if cart_data.include_shipping_costs: shipping_param = 'checkout.shipping_selection.shipping' sid = data.fetch(shipping_param).extracted shipping = Shippings(self.context).get(sid) order.attrs['shipping_method'] = sid order.attrs['shipping_label'] = shipping.label order.attrs['shipping_description'] = shipping.description try: shipping_net = shipping.net(self.items) shipping_vat = shipping.vat(self.items) order.attrs['shipping_net'] = shipping_net order.attrs['shipping_vat'] = shipping_vat order.attrs['shipping'] = shipping_net + shipping_vat # B/C for bda.plone.shipping < 0.4 except NotImplementedError: shipping_net = shipping.calculate(self.items) order.attrs['shipping_net'] = shipping_net order.attrs['shipping_vat'] = Decimal(0) order.attrs['shipping'] = shipping_net # no shipping else: order.attrs['shipping_method'] = 'no_shipping' order.attrs['shipping_label'] = _('no_shipping', default=u'No Shipping') order.attrs['shipping_description'] = '' order.attrs['shipping_net'] = Decimal(0) order.attrs['shipping_vat'] = Decimal(0) order.attrs['shipping'] = Decimal(0) # create order bookings bookings = self.create_bookings(order) # set order state, needed for sorting in orders table order.attrs['state'] = calculate_order_state(bookings) # set order salaried, needed for sorting in orders table order.attrs['salaried'] = ifaces.SALARIED_NO # lookup booking uids, buyable uids and vendor uids booking_uids = list() buyable_uids = list() vendor_uids = set() for booking in bookings: booking_uids.append(booking.attrs['uid']) buyable_uids.append(booking.attrs['buyable_uid']) vendor_uids.add(booking.attrs['vendor_uid']) order.attrs['booking_uids'] = booking_uids order.attrs['buyable_uids'] = buyable_uids order.attrs['vendor_uids'] = list(vendor_uids) # cart discount related information cart_discount = cart_data.discount(self.items) order.attrs['cart_discount_net'] = cart_discount['net'] order.attrs['cart_discount_vat'] = cart_discount['vat'] # create ordernumber orders_soup = get_orders_soup(self.context) ordernumber = create_ordernumber() while self.ordernumber_exists(orders_soup, ordernumber): ordernumber = create_ordernumber() order.attrs['ordernumber'] = ordernumber # add order orders_soup.add(order) # add bookings bookings_soup = get_bookings_soup(self.context) # list containing items where stock threshold has been reached stock_threshold_reached_items = list() for booking in bookings: bookings_soup.add(booking) buyable = get_object_by_uid(self.context, booking.attrs['buyable_uid']) item_stock = get_item_stock(buyable) # no stock applied if item_stock is None: stock_warning_threshold = None else: stock_warning_threshold = item_stock.stock_warning_threshold if stock_warning_threshold: remaining = booking.attrs['remaining_stock_available'] # stock threshold has been reached if remaining <= stock_warning_threshold: stock_threshold_reached_items.append(booking.attrs) if stock_threshold_reached_items: event = events.StockThresholdReached( self.context, self.request, order.attrs['uid'], stock_threshold_reached_items, ) notify(event) # return uid of added order return uid
def save(self, providers, widget, data): super(OrderCheckoutAdapter, self).save(providers, widget, data) order = self.order # order UUID uid = order.attrs['uid'] = uuid.uuid4() # order creator creator = None member = plone.api.user.get_current() if member: creator = member.getId() order.attrs['creator'] = creator # order creation date created = datetime.datetime.now() order.attrs['created'] = created cart_data = get_data_provider(self.context, self.request) # payment related information if cart_data.total > Decimal(0): payment_param = 'checkout.payment_selection.payment' pid = data.fetch(payment_param).extracted payment = Payments(self.context).get(pid) order.attrs['payment_method'] = pid if payment: order.attrs['payment_label'] = payment.label else: order.attrs['payment_label'] = _('unknown', default=u'Unknown') # no payment else: order.attrs['payment_method'] = 'no_payment' order.attrs['payment_label'] = _('no_payment', default=u'No Payment') # shipping related information if cart_data.include_shipping_costs: shipping_param = 'checkout.shipping_selection.shipping' sid = data.fetch(shipping_param).extracted shipping = Shippings(self.context).get(sid) order.attrs['shipping_method'] = sid order.attrs['shipping_label'] = shipping.label order.attrs['shipping_description'] = shipping.description try: shipping_net = shipping.net(self.items) shipping_vat = shipping.vat(self.items) order.attrs['shipping_net'] = shipping_net order.attrs['shipping_vat'] = shipping_vat order.attrs['shipping'] = shipping_net + shipping_vat # B/C for bda.plone.shipping < 0.4 except NotImplementedError: shipping_net = shipping.calculate(self.items) order.attrs['shipping_net'] = shipping_net order.attrs['shipping_vat'] = Decimal(0) order.attrs['shipping'] = shipping_net # no shipping else: order.attrs['shipping_method'] = 'no_shipping' order.attrs['shipping_label'] = _('no_shipping', default=u'No Shipping') order.attrs['shipping_description'] = '' order.attrs['shipping_net'] = Decimal(0) order.attrs['shipping_vat'] = Decimal(0) order.attrs['shipping'] = Decimal(0) # create order bookings bookings = self.create_bookings(order) # set order state, needed for sorting in orders table order.attrs['state'] = calculate_order_state(bookings) # set order salaried, needed for sorting in orders table order.attrs['salaried'] = ifaces.SALARIED_NO # lookup booking uids, buyable uids and vendor uids booking_uids = list() buyable_uids = list() vendor_uids = set() for booking in bookings: booking_uids.append(booking.attrs['uid']) buyable_uids.append(booking.attrs['buyable_uid']) vendor_uids.add(booking.attrs['vendor_uid']) order.attrs['booking_uids'] = booking_uids order.attrs['buyable_uids'] = buyable_uids order.attrs['vendor_uids'] = list(vendor_uids) # cart discount related information # XXX: in order to be able to reliably modify orders, cart discount # rules for this order must be stored instead of the actual # calculated discount. cart_discount = cart_data.discount(self.items) order.attrs['cart_discount_net'] = cart_discount['net'] order.attrs['cart_discount_vat'] = cart_discount['vat'] # create ordernumber orders_soup = get_orders_soup(self.context) ordernumber = create_ordernumber() while self.ordernumber_exists(orders_soup, ordernumber): ordernumber = create_ordernumber() order.attrs['ordernumber'] = ordernumber # add order orders_soup.add(order) # add bookings bookings_soup = get_bookings_soup(self.context) # list containing items where stock threshold has been reached stock_threshold_reached_items = list() for booking in bookings: bookings_soup.add(booking) buyable = get_object_by_uid( self.context, booking.attrs['buyable_uid'] ) item_stock = get_item_stock(buyable) # no stock applied if item_stock is None: stock_warning_threshold = None else: stock_warning_threshold = item_stock.stock_warning_threshold if stock_warning_threshold: remaining = booking.attrs['remaining_stock_available'] # stock threshold has been reached if remaining <= stock_warning_threshold: stock_threshold_reached_items.append(booking.attrs) if stock_threshold_reached_items: event = events.StockThresholdReached( self.context, self.request, order.attrs['uid'], stock_threshold_reached_items, ) notify(event) # return uid of added order return uid
def buyable_url(context, booking): obj = get_object_by_uid(context, booking.attrs['buyable_uid']) if not obj: return None return obj.absolute_url()