Beispiel #1
0
def add_ticket(request, quantity=1, redirect_to='satchmo_cart'):
    formdata = request.POST.copy()
    details = []

    form1 = SelectEventDateForm(request.POST)
    form1.fields['datetime'].queryset = EventDate.objects.all()
    if form1.is_valid():
        datetime = form1.cleaned_data['datetime']
        form2 = SelectPlaceForm(request.POST)
        form2.fields['seat'].queryset = datetime.event.hallscheme.seats.all()
        if form2.is_valid():
            seat = form2.cleaned_data['seat']
            ticket = Ticket.objects.get(seat=seat, datetime=datetime)
            cart = Cart.objects.from_request(request, create=True)
            satchmo_cart_details_query.send(
                    cart,
                    product=ticket.product,
                    quantity=quantity,
                    details=details,
                    request=request,
                    form=formdata
                    )
            try:
                added_item = cart.add_item(ticket.product, number_added=1, details=details)
                added_item.quantity = 1
                added_item.save()
        
            except CartAddProhibited, cap:
                return _product_error(request, ticket.product, cap.message)
        
            # got to here with no error, now send a signal so that listeners can also operate on this form.
            satchmo_cart_add_complete.send(cart, cart=cart, cartitem=added_item, product=ticket.product, request=request, form=formdata)
            satchmo_cart_changed.send(cart, cart=cart, request=request)
        
            if request.is_ajax():
                data = {
                    'id': ticket.product.id,
                    'slug': seat.slug,
                    'name': ticket.product.translated_name(),
                    'item_id': added_item.id,
                    'item_qty': str(round_decimal(quantity, 2)),
                    'item_price': str(added_item.line_total) or "0.00",
                    'cart_count': str(round_decimal(cart.numItems, 2)),
                    'cart_total': str(round_decimal(cart.total, 2)),
                    # Legacy result, for now
                    'results': _("Success"),
                }
        
                return _json_response(data)
            else:
                return redirect(redirect_to)
        else:
            return _json_response({'errors': form2.errors, 'results': _("Error")}, True)
Beispiel #2
0
def _set_quantity(request, force_delete=False):
    """Set the quantity for a specific cartitem.
    Checks to make sure the item is actually in the user's cart.
    """
    cart = Cart.objects.from_request(request, create=False)
    if isinstance(cart, NullCart):
        return (False, None, None, _("No cart to update."))

    cartplaces = config_value('SHOP', 'CART_PRECISION')

    if decimal_too_big(request.POST.get('quantity', 0)):
        return (False,cart,None,_("Bad quantity."))

    if force_delete:
        qty = Decimal('0')
    else:
        try:
            roundfactor = config_value('SHOP', 'CART_ROUNDING')
            qty = round_decimal(request.POST.get('quantity', 0), places=cartplaces, roundfactor=roundfactor, normalize=True)
        except RoundedDecimalError as P:
            return (False, cart, None, _("Bad quantity."))

        if qty < Decimal('0'):
            qty = Decimal('0')

    try:
        itemid = int(request.POST.get('cartitem'))
    except (TypeError, ValueError):
        return (False, cart, None, _("Bad item number."))

    try:
        cartitem = CartItem.objects.get(pk=itemid, cart=cart)
    except CartItem.DoesNotExist:
        return (False, cart, None, _("No such item in your cart."))

    if qty == Decimal('0'):
        cartitem.delete()
        cartitem = NullCartItem(itemid)
    else:
        if config_value('PRODUCT','NO_STOCK_CHECKOUT') == False:
            stock = cartitem.product.items_in_stock
            log.debug('checking stock quantity.  Have %d, need %d', stock, qty)
            if stock < qty:
                return (False, cart, cartitem, _("Unfortunately we only have %(stock)d '%(cartitem_name)s' in stock.") % {'stock': stock, 'cartitem_name': cartitem.product.translated_name()})

        cartitem.quantity = round_decimal(qty, places=cartplaces)
        cartitem.save()

    satchmo_cart_changed.send(cart, cart=cart, request=request)
    return (True, cart, cartitem, "")
Beispiel #3
0
def _set_quantity(request, force_delete=False):
    """Set the quantity for a specific cartitem.
    Checks to make sure the item is actually in the user's cart.
    """
    cart = Cart.objects.from_request(request, create=False)
    if isinstance(cart, NullCart):
        return (False, None, None, _("No cart to update."))

    cartplaces = config_value('SHOP', 'CART_PRECISION')

    if decimal_too_big(request.POST.get('quantity', 0)):
        return (False, cart, None, _("Bad quantity."))

    if force_delete:
        qty = Decimal('0')
    else:
        try:
            roundfactor = config_value('SHOP', 'CART_ROUNDING')
            qty = round_decimal(request.POST.get('quantity', 0),
                                places=cartplaces,
                                roundfactor=roundfactor,
                                normalize=True)
        except RoundedDecimalError, P:
            return (False, cart, None, _("Bad quantity."))

        if qty < Decimal('0'):
            qty = Decimal('0')
Beispiel #4
0
def _render_decimal(value, places=2, min_places=2):

    if value is not None:
        roundfactor = "0." + "0"*(places-1) + "1"
        if value < 0:
            roundfactor = "-" + roundfactor

        value = round_decimal(val=value, places=places, roundfactor=roundfactor, normalize=True)
        log.debug('value: %s' % type(value))
        parts = ("%f" % value).split('.')
        n = parts[0]
        d = ""

        if len(parts) > 0:
            d = parts[1]
        elif min_places:
            d = "0" * min_places

        while len(d) < min_places:
            d = "%s0" % d

        while len(d) > min_places and d[-1] == '0':
            d = d[:-1]

        if len(d) > 0:
            value = "%s.%s" % (n, d)
        else:
            value = n
    return value
Beispiel #5
0
def get_price(request, product_slug):
    """Get base price for a product, returning the answer encoded as JSON."""
    quantity = Decimal('1')

    try:
        product = Product.objects.get_by_site(active=True, slug=product_slug)
    except Product.DoesNotExist:
        return http.HttpResponseNotFound(json_encode(('', _("not available"))), mimetype="text/javascript")

    prod_slug = product.slug

    if request.method == "POST" and request.POST.has_key('quantity'):
        try:
            quantity = round_decimal(request.POST['quantity'], places=2, roundfactor=.25)
        except RoundedDecimalError:
            quantity = Decimal('1.0')
            log.warn("Could not parse a decimal from '%s', returning '1.0'", request.POST['quantity'])

    if 'ConfigurableProduct' in product.get_subtypes():
        cp = product.configurableproduct
        chosen_options = optionids_from_post(cp, request.POST)
        pvp = cp.get_product_from_options(chosen_options)

        if not pvp:
            return http.HttpResponse(json_encode(('', _("not available"))), mimetype="text/javascript")
        prod_slug = pvp.slug
        price = moneyfmt(pvp.get_qty_price(quantity))
    else:
        price = moneyfmt(product.get_qty_price(quantity))

    if not price:
        return http.HttpResponse(json_encode(('', _("not available"))), mimetype="text/javascript")

    return http.HttpResponse(json_encode((prod_slug, price)), mimetype="text/javascript")
Beispiel #6
0
Datei: cart.py Projekt: 34/T
def add(request, id=0, redirect_to='satchmo_cart'):
    """Add an item to the cart."""
    log.debug('FORM: %s', request.POST)
    formdata = request.POST.copy()
    productslug = None

    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')


    if formdata.has_key('productname'):
        productslug = formdata['productname']
    try:
        product, details = product_from_post(productslug, formdata)

        if not (product and product.active):
            log.debug("product %s is not active" % productslug)
            return bad_or_missing(request, _("That product is not available at the moment."))
        else:
            log.debug("product %s is active" % productslug)

    except (Product.DoesNotExist, MultiValueDictKeyError):
        log.debug("Could not find product: %s", productslug)
        return bad_or_missing(request, _('The product you have requested does not exist.'))

    # First we validate that the number isn't too big.
    if decimal_too_big(formdata['quantity']):
        return _product_error(request, product, _("Please enter a smaller number."))

    # Then we validate that we can round it appropriately.
    try:
        quantity = round_decimal(formdata['quantity'], places=cartplaces, roundfactor=roundfactor)
    except RoundedDecimalError, P:
        return _product_error(request, product,
            _("Invalid quantity."))
Beispiel #7
0
def _render_decimal(value, places=2, min_places=2):

    if value is not None:
        roundfactor = "0." + "0" * (places - 1) + "1"
        if value < 0:
            roundfactor = "-" + roundfactor

        value = round_decimal(val=value,
                              places=places,
                              roundfactor=roundfactor,
                              normalize=True)
        log.debug('value: %s' % type(value))
        parts = ("%f" % value).split('.')
        n = parts[0]
        d = ""

        if len(parts) > 0:
            d = parts[1]
        elif min_places:
            d = "0" * min_places

        while len(d) < min_places:
            d = "%s0" % d

        while len(d) > min_places and d[-1] == '0':
            d = d[:-1]

        if len(d) > 0:
            value = "%s.%s" % (n, d)
        else:
            value = n
    return value
Beispiel #8
0
def add(request, id=0, redirect_to='satchmo_cart'):
    """Add an item to the cart."""
    log.debug('FORM: %s', request.POST)
    formdata = request.POST.copy()
    productslug = None

    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')

    if formdata.has_key('productname'):
        productslug = formdata['productname']
    try:
        product, details = product_from_post(productslug, formdata)

        if not (product and product.active):
            log.debug("product %s is not active" % productslug)
            return bad_or_missing(
                request, _("That product is not available at the moment."))
        else:
            log.debug("product %s is active" % productslug)

    except (Product.DoesNotExist, MultiValueDictKeyError):
        log.debug("Could not find product: %s", productslug)
        return bad_or_missing(
            request, _('The product you have requested does not exist.'))

    # First we validate that the number isn't too big.
    if decimal_too_big(formdata['quantity']):
        return _product_error(request, product,
                              _("Please enter a smaller number."))

    # Then we validate that we can round it appropriately.
    try:
        quantity = round_decimal(formdata['quantity'],
                                 places=cartplaces,
                                 roundfactor=roundfactor)
    except RoundedDecimalError:
        return _product_error(request, product, _("Invalid quantity."))

    if quantity <= Decimal('0'):
        return _product_error(request, product,
                              _("Please enter a positive number."))

    cart = Cart.objects.from_request(request, create=True)
    # send a signal so that listeners can update product details before we add it to the cart.
    satchmo_cart_details_query.send(cart,
                                    product=product,
                                    quantity=quantity,
                                    details=details,
                                    request=request,
                                    form=formdata)
    try:
        added_item = cart.add_item(product,
                                   number_added=quantity,
                                   details=details)

    except CartAddProhibited, cap:
        return _product_error(request, product, cap.message)
Beispiel #9
0
def add(request, id=0, redirect_to='satchmo_cart'):
    """Add an item to the cart."""
    log.debug('FORM: %s', request.POST)
    formdata = request.POST.copy()
    productslug = None

    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')


    if formdata.has_key('productname'):
        productslug = formdata['productname']
    try:
        product, details = product_from_post(productslug, formdata)

        if not (product and product.active):
            log.debug("product %s is not active" % productslug)
            return bad_or_missing(request, _("That product is not available at the moment."))
        else:
            log.debug("product %s is active" % productslug)

    except (Product.DoesNotExist, MultiValueDictKeyError):
        log.debug("Could not find product: %s", productslug)
        return bad_or_missing(request, _('The product you have requested does not exist.'))

    # First we validate that the number isn't too big.
    if decimal_too_big(formdata['quantity']):
        return _product_error(request, product, _("Please enter a smaller number."))

    # Then we validate that we can round it appropriately.
    try:
        quantity = round_decimal(formdata['quantity'], places=cartplaces, roundfactor=roundfactor)
    except RoundedDecimalError:
        return _product_error(request, product,
            _("Invalid quantity."))

    if quantity <= Decimal('0'):
        return _product_error(request, product,
            _("Please enter a positive number."))

    cart = Cart.objects.from_request(request, create=True)
    # send a signal so that listeners can update product details before we add it to the cart.
    satchmo_cart_details_query.send(
            cart,
            product=product,
            quantity=quantity,
            details=details,
            request=request,
            form=formdata
            )
    try:
        added_item = cart.add_item(product, number_added=quantity, details=details)

    except CartAddProhibited, cap:
        return _product_error(request, product, cap.message)
Beispiel #10
0
def set_quantity_ajax(request, template="shop/json.html"):
    """Set the quantity for a cart item, returning results formatted for handling by script.
    """
    data = {}
    if not request.POST:
        data['results'] = False
        data['errors'] = _('Internal error: please submit as a POST')

    else:
        success, cart, cartitem, errors = _set_quantity(request)

        data['results'] = success
        data['errors'] = errors

        # note we have to convert Decimals to strings, since simplejson doesn't know about Decimals
        if cart:
            carttotal = str(round_decimal(cart.total, 2))
            cartqty = cart.numItems
        else:
            carttotal = "0.00"
            cartqty = Decimal('0')

        data['cart_total'] = carttotal
        data['cart_count'] = cartqty

        if cartitem:
            itemid = cartitem.id
            itemqty = cartitem.quantity
            price = str(round_decimal(cartitem.line_total, 2))
        else:
            itemid = -1
            itemqty = Decimal('0')
            price = "0.00"

        data['item_id'] = itemid
        data['item_qty'] = itemqty
        data['item_price'] = price

    encoded = JSONEncoder().encode(data)
    encoded = mark_safe(encoded)
    return render_to_response(template, {'json': encoded})
Beispiel #11
0
    def save(self, cart, request):
        log.debug('saving')
        self.full_clean()
        cartplaces = config_value('SHOP', 'CART_PRECISION')
        roundfactor = config_value('SHOP', 'CART_ROUNDING')
        site = Site.objects.get_current()

        for name, value in self.cleaned_data.items():
            opt, key = name.split('__')
            log.debug('%s=%s', opt, key)

            quantity = 0
            product = None

            if opt == 'qty':
                try:
                    quantity = round_decimal(value,
                                             places=cartplaces,
                                             roundfactor=roundfactor)
                except RoundedDecimalError:
                    quantity = 0

            if not key in self.slugs:
                log.debug('caught attempt to add product not in the form: %s',
                          key)
            else:
                try:
                    product = Product.objects.get(slug=key, site=site)
                except Product.DoesNotExist:
                    log.debug(
                        'caught attempt to add an non-existent product, ignoring: %s',
                        key)

            if product and quantity > Decimal('0'):
                log.debug('Adding %s=%s to cart from MultipleProductForm', key,
                          value)
                details = []
                formdata = request.POST
                satchmo_cart_details_query.send(cart,
                                                product=product,
                                                quantity=quantity,
                                                details=details,
                                                request=request,
                                                form=formdata)
                added_item = cart.add_item(product,
                                           number_added=quantity,
                                           details=details)
                satchmo_cart_add_complete.send(cart,
                                               cart=cart,
                                               cartitem=added_item,
                                               product=product,
                                               request=request,
                                               form=formdata)
def normalize_decimal(value, args=""):
    """
    PARTIAL UNIT ROUNDING DECIMAL
    Converts a valid float, integer, or string to a decimal number with a specified
    number of decimal places, performs "partial unit rounding", and decimal normalization.

    Usage:
        val|normalize_decimal
        val|normalize_decimal:'places=2'
        val|normalize_decimal:'places=2:roundfactor=.5'
        val|normalize_decimal:'places=2:roundfactor=.5:normalize=False'

    val
        The value to be converted and optionally formated to decimal.
    places 
        The decimal place precision is defined by integer "places" and
        must be <= the precision defined in the decimal.Decimal context.  roundfactor represents
        the maximum number of decimal places to display if normalize is False.

    roundfactor
        (partial unit rounding factor) If roundfactor is between 0 and 1, roundfactor rounds up
        (positive roundfactor value) or down (negative roundfactor value) in factional "roundfactor" increments.
    
    normalize
        If normalize is True (any value other than False), then rightmost zeros are truncated.

    General Filter/Template Usage.
        normalize_decimal is generally used without parameters in the template.
        Defaults are: places=2, roundfactor=None, normalize=True
        If normalize_decimal is not used as a template filter, the value (quantity)
        will display the full decimal value in the template field.
    """

    if value == '' or value is None:
        return value
    args, kwargs = get_filter_args(args,
                                   keywords=('places', 'roundfactor',
                                             'normalize'),
                                   intargs=('places', ),
                                   boolargs=('normalize', ),
                                   stripquotes=True)

    if not 'places' in kwargs:
        kwargs['places'] = 2

    try:
        return mark_safe(str(round_decimal(val=value, **kwargs)))

    except RoundedDecimalError as e:
        log.error("normalize_decimal error val=%s, id-%s, msg=%s",
                  (e.val, e.id, e.msg))
        return value
Beispiel #13
0
def get_price_detail(request, product_slug):
    """Get all price details for a product, returning the response encoded as JSON."""
    results = {"success": False, "message": _("not available")}
    price = None

    if request.method == "POST":
        reqdata = request.POST
    else:
        reqdata = request.GET

    try:
        product = Product.objects.get_by_site(active=True, slug=product_slug)
        found = True

        prod_slug = product.slug

        if 'quantity' in reqdata:
            try:
                quantity = round_decimal(reqdata['quantity'],
                                         places=2,
                                         roundfactor=.25)
            except RoundedDecimalError:
                quantity = Decimal('1.0')
                log.warn(
                    "Could not parse a decimal from '%s', returning '1.0'",
                    reqdata['quantity'])
        else:
            quantity = Decimal('1.0')

        if 'ConfigurableProduct' in product.get_subtypes():
            cp = product.configurableproduct
            chosen_options = optionids_from_post(cp, reqdata)
            product = cp.get_product_from_options(chosen_options)

        if product:
            price = product.get_qty_price(quantity)

            results['slug'] = product.slug
            results['price'] = float(price)
            results['success'] = True
            results['message'] = ""

    except Product.DoesNotExist:
        found = False

    data = json_encode(results)
    if found:
        return http.HttpResponse(data, content_type="text/javascript")
    else:
        return http.HttpResponseNotFound(data, content_type="text/javascript")
Beispiel #14
0
def get_price_detail(request, product_slug):
    """Get all price details for a product, returning the response encoded as JSON."""
    results = {
        "success" : False,
        "message" :  _("not available")
    }
    price = None

    if request.method=="POST":
        reqdata = request.POST
    else:
        reqdata = request.GET

    try:
        product = Product.objects.get_by_site(active=True, slug=product_slug)
        found = True

        prod_slug = product.slug

        if reqdata.has_key('quantity'):
            try:
                quantity = round_decimal(reqdata['quantity'], places=2, roundfactor=.25)
            except RoundedDecimalError:
                quantity = Decimal('1.0')
                log.warn("Could not parse a decimal from '%s', returning '1.0'", reqdata['quantity'])
        else:
            quantity = Decimal('1.0')

        if 'ConfigurableProduct' in product.get_subtypes():
            cp = product.configurableproduct
            chosen_options = optionids_from_post(cp, reqdata)
            product = cp.get_product_from_options(chosen_options)

        if product:
            price = product.get_qty_price(quantity)

            results['slug'] = product.slug
            results['price'] = float(price)
            results['success'] = True
            results['message'] = ""

    except Product.DoesNotExist:
        found = False

    data = json_encode(results)
    if found:
        return http.HttpResponse(data, mimetype="text/javascript")
    else:
        return http.HttpResponseNotFound(data, mimetype="text/javascript")
Beispiel #15
0
def normalize_decimal(value, args=""):
    """
    PARTIAL UNIT ROUNDING DECIMAL
    Converts a valid float, integer, or string to a decimal number with a specified
    number of decimal places, performs "partial unit rounding", and decimal normalization.

    Usage:
        val|normalize_decimal
        val|normalize_decimal:'places=2'
        val|normalize_decimal:'places=2:roundfactor=.5'
        val|normalize_decimal:'places=2:roundfactor=.5:normalize=False'

    val
        The value to be converted and optionally formated to decimal.
    places 
        The decimal place precision is defined by integer "places" and
        must be <= the precision defined in the decimal.Decimal context.  roundfactor represents
        the maximum number of decimal places to display if normalize is False.

    roundfactor
        (partial unit rounding factor) If roundfactor is between 0 and 1, roundfactor rounds up
        (positive roundfactor value) or down (negative roundfactor value) in factional "roundfactor" increments.
    
    normalize
        If normalize is True (any value other than False), then rightmost zeros are truncated.

    General Filter/Template Usage.
        normalize_decimal is generally used without parameters in the template.
        Defaults are: places=2, roundfactor=None, normalize=True
        If normalize_decimal is not used as a template filter, the value (quantity)
        will display the full decimal value in the template field.
    """
    
    if value == '' or value is None:
        return value
    args, kwargs = get_filter_args(args,
        keywords=('places','roundfactor', 'normalize'),
        intargs=('places',),
        boolargs=('normalize',), stripquotes=True)

    if not 'places' in kwargs:
        kwargs['places'] = 2

    try:
        return mark_safe(str(round_decimal(val=value, **kwargs)))

    except RoundedDecimalError, e:
        log.error("normalize_decimal error val=%s, id-%s, msg=%s", (e.val, e.id, e.msg))
        return value
Beispiel #16
0
    def save(self, cart, request):
        log.debug('saving');
        self.full_clean()
        cartplaces = config_value('SHOP', 'CART_PRECISION')
        roundfactor = config_value('SHOP', 'CART_ROUNDING')    
        
        for name, value in self.cleaned_data.items():
            opt, key = name.split('__')
            log.debug('%s=%s', opt, key)

            items = {}
            quantity = 0
            product = None

            if opt=='qty':                
                try:
                    quantity = round_decimal(value, places=cartplaces, roundfactor=roundfactor)
                except RoundedDecimalError, P:
                    quantity = 0
                    
            if not key in self.slugs:
                log.debug('caught attempt to add product not in the form: %s', key)
            else:
                try:
                    product = Product.objects.get(slug=key)
                except Product.DoesNotExist:
                    log.debug('caught attempt to add an non-existent product, ignoring: %s', key)
                    
            if product and quantity > Decimal('0'):                
                log.debug('Adding %s=%s to cart from MultipleProductForm', key, value)
                details = {}
                formdata = request.POST
                satchmo_cart_details_query.send(
                    cart,
                    product=product,
                    quantity=quantity,
                    details=details,
                    request=request,
                    form=formdata
                )
                added_item = cart.add_item(product, number_added=quantity, details=details)
                satchmo_cart_add_complete.send(cart, cart=cart, cartitem=added_item, 
                    product=product, request=request, form=formdata)
Beispiel #17
0
def _set_quantity(request, force_delete=False):
    """Set the quantity for a specific cartitem.
    Checks to make sure the item is actually in the user's cart.
    """
    cart = Cart.objects.from_request(request, create=False)
    if isinstance(cart, NullCart):
        return (False, None, None, _("No cart to update."))
    
    cartplaces = config_value('SHOP', 'CART_PRECISION')
    if force_delete:
        qty = Decimal('0')
    else:
        try:
            roundfactor = config_value('SHOP', 'CART_ROUNDING')
            qty = round_decimal(request.POST.get('quantity', 0), places=cartplaces, roundfactor=roundfactor, normalize=True)
        except RoundedDecimalError, P:
            return (False, cart, None, _("Bad quantity."))
            
        if qty < Decimal('0'):
            qty = Decimal('0')
Beispiel #18
0
def get_price(request, product_slug):
    """Get base price for a product, returning the answer encoded as JSON."""
    quantity = Decimal('1')

    try:
        product = Product.objects.get_by_site(active=True, slug=product_slug)
    except Product.DoesNotExist:
        return http.HttpResponseNotFound(json_encode(('', _("not available"))),
                                         content_type="text/javascript")

    prod_slug = product.slug

    if request.method == "POST" and 'quantity' in request.POST:
        try:
            quantity = round_decimal(request.POST['quantity'],
                                     places=2,
                                     roundfactor=.25)
        except RoundedDecimalError:
            quantity = Decimal('1.0')
            log.warn("Could not parse a decimal from '%s', returning '1.0'",
                     request.POST['quantity'])

    if 'ConfigurableProduct' in product.get_subtypes():
        cp = product.configurableproduct
        chosen_options = optionids_from_post(cp, request.POST)
        pvp = cp.get_product_from_options(chosen_options)

        if not pvp:
            return http.HttpResponse(json_encode(('', _("not available"))),
                                     content_type="text/javascript")
        prod_slug = pvp.slug
        price = moneyfmt(pvp.get_qty_price(quantity))
    else:
        price = moneyfmt(product.get_qty_price(quantity))

    if not price:
        return http.HttpResponse(json_encode(('', _("not available"))),
                                 content_type="text/javascript")

    return http.HttpResponse(json_encode((prod_slug, price)),
                             content_type="text/javascript")
Beispiel #19
0
def _render_decimal(value, places=2, min_places=2):
    # Check to make sure this is a Decimal before we try to round
    # and format. If it's not, just pass it on.
    # The admin validation will handle making sure only valid values get
    # saved.
    bad_decimal = False
    try:
        Decimal(value)
    except:
        bad_decimal = True
    if value is not None and not bad_decimal:
        roundfactor = "0." + "0" * (places - 1) + "1"
        if value < 0:
            roundfactor = "-" + roundfactor

        value = round_decimal(val=value,
                              places=places,
                              roundfactor=roundfactor,
                              normalize=True)
        log.debug('value: %s' % type(value))
        parts = ("%f" % value).split('.')
        n = parts[0]
        d = ""

        if len(parts) > 0:
            d = parts[1]
        elif min_places:
            d = "0" * min_places

        while len(d) < min_places:
            d = "%s0" % d

        while len(d) > min_places and d[-1] == '0':
            d = d[:-1]

        if len(d) > 0:
            value = "%s.%s" % (n, d)
        else:
            value = n
    return value
Beispiel #20
0
def add(request, id=0, redirect_to='satchmo_cart'):
    """Add an item to the cart."""
    log.debug('FORM: %s', request.POST)
    formdata = request.POST.copy()
    productslug = None

    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')

    if formdata.has_key('productname'):
        productslug = formdata['productname']
    try:
        product, details = product_from_post(productslug, formdata)

        if not (product and product.active):
            log.debug("product %s is not active" % productslug)
            return bad_or_missing(
                request, _("That product is not available at the moment."))
        else:
            log.debug("product %s is active" % productslug)

    except (Product.DoesNotExist, MultiValueDictKeyError):
        log.debug("Could not find product: %s", productslug)
        return bad_or_missing(
            request, _('The product you have requested does not exist.'))

    # First we validate that the number isn't too big.
    if decimal_too_big(formdata['quantity']):
        return _product_error(request, product,
                              _("Please enter a smaller number."))

    # Then we validate that we can round it appropriately.
    try:
        quantity = round_decimal(formdata['quantity'],
                                 places=cartplaces,
                                 roundfactor=roundfactor)
    except RoundedDecimalError, P:
        return _product_error(request, product, _("Invalid quantity."))
Beispiel #21
0
def _render_decimal(value, places=2, min_places=2):
    # Check to make sure this is a Decimal before we try to round
    # and format. If it's not, just pass it on.
    # The admin validation will handle making sure only valid values get
    # saved.
    bad_decimal = False
    try:
        Decimal(value)
    except:
        bad_decimal = True
    if value is not None and not bad_decimal:
        roundfactor = "0." + "0"*(places-1) + "1"
        if value < 0:
            roundfactor = "-" + roundfactor

        value = round_decimal(val=value, places=places, roundfactor=roundfactor, normalize=True)
        log.debug('value: %s' % type(value))
        parts = ("%f" % value).split('.')
        n = parts[0]
        d = ""

        if len(parts) > 0:
            d = parts[1]
        elif min_places:
            d = "0" * min_places

        while len(d) < min_places:
            d = "%s0" % d

        while len(d) > min_places and d[-1] == '0':
            d = d[:-1]

        if len(d) > 0:
            value = "%s.%s" % (n, d)
        else:
            value = n
    return value
Beispiel #22
0
    def changelist_view(self, request, extra_context=None):
        "The 'change list' admin view for this model."
        from django.contrib.admin.views.main import ERROR_FLAG
        opts = self.model._meta
        app_label = opts.app_label
        if not self.has_change_permission(request, None):
            raise PermissionDenied

        # Check actions to see if any are available on this changelist
        actions = self.get_actions(request)

        # Remove action checkboxes if there aren't any actions available.
        list_display = list(self.list_display)
        if not actions:
            try:
                list_display.remove('action_checkbox')
            except ValueError:
                pass

        ChangeList = self.get_changelist(request)
        try:
            cl = ChangeList(request, self.model, list_display,
                            self.list_display_links, self.list_filter,
                            self.date_hierarchy, self.search_fields,
                            self.list_select_related, self.list_per_page,
                            self.list_editable, self)
        except IncorrectLookupParameters:
            # Wacky lookup parameters were given, so redirect to the main
            # changelist page, without parameters, and pass an 'invalid=1'
            # parameter via the query string. If wacky parameters were given
            # and the 'invalid=1' parameter was already in the query string,
            # something is screwed up with the database, so display an error
            # page.
            if ERROR_FLAG in request.GET.keys():
                return render_to_response('admin/invalid_setup.html',
                                          {'title': _('Database error')})
            return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')

        # If the request was POSTed, this might be a bulk action or a bulk
        # edit. Try to look up an action or confirmation first, but if this
        # isn't an action the POST will fall through to the bulk edit check,
        # below.
        action_failed = False
        selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)

        # Actions with no confirmation
        if (actions and request.method == 'POST' and 'index' in request.POST
                and '_save' not in request.POST):
            if selected:
                response = self.response_action(request,
                                                queryset=cl.get_query_set())
                if response:
                    return response
                else:
                    action_failed = True
            else:
                msg = _("Items must be selected in order to perform "
                        "actions on them. No items have been changed.")
                self.message_user(request, msg)
                action_failed = True

        # Actions with confirmation
        if (actions and request.method == 'POST'
                and helpers.ACTION_CHECKBOX_NAME in request.POST
                and 'index' not in request.POST
                and '_save' not in request.POST):
            if selected:
                response = self.response_action(request,
                                                queryset=cl.get_query_set())
                if response:
                    return response
                else:
                    action_failed = True

        # If we're allowing changelist editing, we need to construct a formset
        # for the changelist given all the fields to be edited. Then we'll
        # use the formset to validate/process POSTed data.
        formset = cl.formset = None

        # Handle POSTed bulk-edit data.
        if (request.method == "POST" and cl.list_editable
                and '_save' in request.POST and not action_failed):
            FormSet = self.get_changelist_formset(request)
            formset = cl.formset = FormSet(request.POST,
                                           request.FILES,
                                           queryset=cl.result_list)
            if formset.is_valid():
                changecount = 0
                for form in formset.forms:
                    if form.has_changed():
                        obj = self.save_form(request, form, change=True)
                        self.save_model(request, obj, form, change=True)
                        form.save_m2m()
                        change_msg = self.construct_change_message(
                            request, form, None)
                        self.log_change(request, obj, change_msg)
                        changecount += 1

                if changecount:
                    if changecount == 1:
                        name = force_unicode(opts.verbose_name)
                    else:
                        name = force_unicode(opts.verbose_name_plural)
                    msg = ungettext(
                        "%(count)s %(name)s was changed successfully.",
                        "%(count)s %(name)s were changed successfully.",
                        changecount) % {
                            'count': changecount,
                            'name': name,
                            'obj': force_unicode(obj)
                        }
                    self.message_user(request, msg)

                return HttpResponseRedirect(request.get_full_path())

        # Handle GET -- construct a formset for display.
        elif cl.list_editable:
            FormSet = self.get_changelist_formset(request)
            formset = cl.formset = FormSet(queryset=cl.result_list)

        # Build the list of media to be used by the formset.
        if formset:
            media = self.media + formset.media
        else:
            media = self.media

        # Build the action form and populate it with available actions.
        if actions:
            action_form = self.action_form(auto_id=None)
            action_form.fields['action'].choices = self.get_action_choices(
                request)
        else:
            action_form = None

        selection_note_all = ungettext('%(total_count)s selected',
                                       'All %(total_count)s selected',
                                       cl.result_count)

        # Calculate total
        orders_total = 0
        for order in cl.result_list:
            orders_total += order.total

        context = {
            'module_name':
            force_unicode(opts.verbose_name_plural),
            'selection_note':
            _('0 of %(cnt)s selected') % {
                'cnt': len(cl.result_list)
            },
            'selection_note_all':
            selection_note_all % {
                'total_count': cl.result_count
            },
            'title':
            cl.title,
            'is_popup':
            cl.is_popup,
            'cl':
            cl,
            'media':
            media,
            'has_add_permission':
            self.has_add_permission(request),
            'root_path':
            self.admin_site.root_path,
            'app_label':
            app_label,
            'action_form':
            action_form,
            'actions_on_top':
            self.actions_on_top,
            'actions_on_bottom':
            self.actions_on_bottom,
            'actions_selection_counter':
            self.actions_selection_counter,
            'orders_total':
            round_decimal(val=orders_total,
                          places=2,
                          roundfactor='0.001',
                          normalize=True)
        }
        context.update(extra_context or {})
        context_instance = template.RequestContext(
            request, current_app=self.admin_site.name)
        return render_to_response('admin/orders/change_list.html',
                                  context,
                                  context_instance=context_instance)
Beispiel #23
0
    def testRoundingDecimals(self):
        """Test Partial Unit Rounding Decimal Conversion behavior"""
        val = round_decimal(val=3.40, places=5, roundfactor=.5, normalize=True)
        self.assertEqual(val, Decimal("3.5"))

        val = round_decimal(val=3.40,
                            places=5,
                            roundfactor=-.5,
                            normalize=True)
        self.assertEqual(val, Decimal("3"))

        val = round_decimal(val=0, places=5, roundfactor=-.5, normalize=False)
        self.assertEqual(val, Decimal("0.00000"))

        val = round_decimal(0, 5, -.5, False)
        self.assertEqual(val, Decimal("0.00000"))

        val = round_decimal(0)
        self.assertEqual(val, Decimal("0"))

        val = round_decimal(3.23, 4, -.25)
        self.assertEqual(val, Decimal("3"))

        val = round_decimal(-3.23, 4, -.25)
        self.assertEqual(val, Decimal("-3"))
        val = round_decimal(-3.23, 4, .25)
        self.assertEqual(val, Decimal("-3.25"))

        val = round_decimal(3.23, 4, .25)
        self.assertEqual(val, Decimal("3.25"))

        val = round_decimal(3.23, 4, .25, False)
        self.assertEqual(val, Decimal("3.2500"))

        val = round_decimal(3.23, 1, .25, False)
        self.assertEqual(val, Decimal("3.2"))

        val = round_decimal(2E+1, places=2)
        self.assertEqual(val, Decimal('20.00'))
Beispiel #24
0
def productvariation_details(product, include_tax, user, create=False):
    """Build the product variation details, for conversion to javascript.

    Returns variation detail dictionary built like so:
    details = {
        "OPTION_KEY" : {
            "SLUG": "Variation Slug",
            "PRICE" : {"qty" : "$price", [...]},
            "SALE" : {"qty" : "$price", [...]},
            "TAXED" : "$taxed price",   # omitted if no taxed price requested
            "QTY" : 1
        },
        [...]
    }
    """

    ignore_stock = config_value('PRODUCT', 'NO_STOCK_CHECKOUT')
    discount = find_best_auto_discount(product)
    use_discount = discount and discount.percentage > 0

    if include_tax:
        from tax.utils import get_tax_processor
        taxer = get_tax_processor(user=user)
        tax_class = product.taxClass

    details = {'SALE': use_discount}

    variations = ProductPriceLookup.objects.filter(
        parentid=product.id).order_by("-price")
    if variations.count() == 0:
        if create:
            log.debug('Creating price lookup for %s', product)
            ProductPriceLookup.objects.smart_create_for_product(product)
            variations = ProductPriceLookup.objects.filter(
                parentid=product.id).order_by("-price")
        else:
            log.warning(
                'You must run satchmo_rebuild_pricing and add it to a cron-job to run every day, or else the product details will not work for product detail pages.'
            )
    for detl in variations:
        key = detl.key
        if details.has_key(key):
            detail = details[key]
            qty = detl.quantity
        else:
            detail = {}
            detail['SLUG'] = detl.productslug

            if not detl.active:
                qty = round_decimal('-1.0')
            elif ignore_stock:
                qty = round_decimal('10000.0')
            else:
                qty = round_decimal(detl.items_in_stock)

            detail['QTY'] = round_decimal(qty)

            detail['PRICE'] = {}

            if use_discount:
                detail['SALE'] = {}

            if include_tax:
                detail['TAXED'] = {}
                if use_discount:
                    detail['TAXED_SALE'] = {}

            if detl.productimage_set:
                detail['ADDITIONAL_IMAGES'] = [
                    u"%s" % prodimg.picture
                    for prodimg in detl.productimage_set.all()
                ]

            details[key] = detail

        qtykey = "%d" % detl.quantity

        price = detl.dynamic_price

        detail['PRICE'][qtykey] = moneyfmt(price)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(
                calc_discounted_by_percentage(price, discount.percentage))

        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price)
            if use_discount:
                detail['TAXED_SALE'][qtykey] = moneyfmt(
                    calc_discounted_by_percentage(tax_price,
                                                  discount.percentage))

    return details
Beispiel #25
0
 def _round(val, places=2):
     return str(round_decimal(val=val, places=places, normalize=False))
Beispiel #26
0
    def testRoundingDecimals(self):
        """Test Partial Unit Rounding Decimal Conversion behavior"""
        val = round_decimal(val=3.40, places=5, roundfactor=.5, normalize=True)
        self.assertEqual(val, Decimal("3.5"))

        val = round_decimal(val=3.40, places=5, roundfactor=-.5, normalize=True)
        self.assertEqual(val, Decimal("3"))

        val = round_decimal(val=0, places=5, roundfactor=-.5, normalize=False)
        self.assertEqual(val, Decimal("0.00000"))

        val = round_decimal(0, 5, -.5, False)
        self.assertEqual(val, Decimal("0.00000"))

        val = round_decimal(0)
        self.assertEqual(val, Decimal("0"))

        val = round_decimal(3.23,4,-.25)
        self.assertEqual(val, Decimal("3"))

        val = round_decimal(-3.23,4,-.25)
        self.assertEqual(val, Decimal("-3"))
        val = round_decimal(-3.23,4,.25)
        self.assertEqual(val, Decimal("-3.25"))

        val = round_decimal(3.23,4,.25)
        self.assertEqual(val, Decimal("3.25"))

        val = round_decimal(3.23,4,.25,False)
        self.assertEqual(val, Decimal("3.2500"))

        val = round_decimal(3.23,1,.25,False)
        self.assertEqual(val, Decimal("3.2"))

        val = round_decimal(2E+1, places=2)
        self.assertEqual(val, Decimal('20.00'))
Beispiel #27
0
    def changelist_view(self, request, extra_context=None):
        "The 'change list' admin view for this model."
        from django.contrib.admin.views.main import ERROR_FLAG

        opts = self.model._meta
        app_label = opts.app_label
        if not self.has_change_permission(request, None):
            raise PermissionDenied

        # Check actions to see if any are available on this changelist
        actions = self.get_actions(request)

        # Remove action checkboxes if there aren't any actions available.
        list_display = list(self.list_display)
        if not actions:
            try:
                list_display.remove("action_checkbox")
            except ValueError:
                pass

        ChangeList = self.get_changelist(request)
        try:
            cl = ChangeList(
                request,
                self.model,
                list_display,
                self.list_display_links,
                self.list_filter,
                self.date_hierarchy,
                self.search_fields,
                self.list_select_related,
                self.list_per_page,
                self.list_editable,
                self,
            )
        except IncorrectLookupParameters:
            # Wacky lookup parameters were given, so redirect to the main
            # changelist page, without parameters, and pass an 'invalid=1'
            # parameter via the query string. If wacky parameters were given
            # and the 'invalid=1' parameter was already in the query string,
            # something is screwed up with the database, so display an error
            # page.
            if ERROR_FLAG in request.GET.keys():
                return render_to_response("admin/invalid_setup.html", {"title": _("Database error")})
            return HttpResponseRedirect(request.path + "?" + ERROR_FLAG + "=1")

        # If the request was POSTed, this might be a bulk action or a bulk
        # edit. Try to look up an action or confirmation first, but if this
        # isn't an action the POST will fall through to the bulk edit check,
        # below.
        action_failed = False
        selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)

        # Actions with no confirmation
        if actions and request.method == "POST" and "index" in request.POST and "_save" not in request.POST:
            if selected:
                response = self.response_action(request, queryset=cl.get_query_set())
                if response:
                    return response
                else:
                    action_failed = True
            else:
                msg = _("Items must be selected in order to perform " "actions on them. No items have been changed.")
                self.message_user(request, msg)
                action_failed = True

        # Actions with confirmation
        if (
            actions
            and request.method == "POST"
            and helpers.ACTION_CHECKBOX_NAME in request.POST
            and "index" not in request.POST
            and "_save" not in request.POST
        ):
            if selected:
                response = self.response_action(request, queryset=cl.get_query_set())
                if response:
                    return response
                else:
                    action_failed = True

        # If we're allowing changelist editing, we need to construct a formset
        # for the changelist given all the fields to be edited. Then we'll
        # use the formset to validate/process POSTed data.
        formset = cl.formset = None

        # Handle POSTed bulk-edit data.
        if request.method == "POST" and cl.list_editable and "_save" in request.POST and not action_failed:
            FormSet = self.get_changelist_formset(request)
            formset = cl.formset = FormSet(request.POST, request.FILES, queryset=cl.result_list)
            if formset.is_valid():
                changecount = 0
                for form in formset.forms:
                    if form.has_changed():
                        obj = self.save_form(request, form, change=True)
                        self.save_model(request, obj, form, change=True)
                        form.save_m2m()
                        change_msg = self.construct_change_message(request, form, None)
                        self.log_change(request, obj, change_msg)
                        changecount += 1

                if changecount:
                    if changecount == 1:
                        name = force_unicode(opts.verbose_name)
                    else:
                        name = force_unicode(opts.verbose_name_plural)
                    msg = ungettext(
                        "%(count)s %(name)s was changed successfully.",
                        "%(count)s %(name)s were changed successfully.",
                        changecount,
                    ) % {"count": changecount, "name": name, "obj": force_unicode(obj)}
                    self.message_user(request, msg)

                return HttpResponseRedirect(request.get_full_path())

        # Handle GET -- construct a formset for display.
        elif cl.list_editable:
            FormSet = self.get_changelist_formset(request)
            formset = cl.formset = FormSet(queryset=cl.result_list)

        # Build the list of media to be used by the formset.
        if formset:
            media = self.media + formset.media
        else:
            media = self.media

        # Build the action form and populate it with available actions.
        if actions:
            action_form = self.action_form(auto_id=None)
            action_form.fields["action"].choices = self.get_action_choices(request)
        else:
            action_form = None

        selection_note_all = ungettext("%(total_count)s selected", "All %(total_count)s selected", cl.result_count)

        # Calculate total
        orders_total = 0
        for order in cl.result_list:
            orders_total += order.total

        context = {
            "module_name": force_unicode(opts.verbose_name_plural),
            "selection_note": _("0 of %(cnt)s selected") % {"cnt": len(cl.result_list)},
            "selection_note_all": selection_note_all % {"total_count": cl.result_count},
            "title": cl.title,
            "is_popup": cl.is_popup,
            "cl": cl,
            "media": media,
            "has_add_permission": self.has_add_permission(request),
            "root_path": self.admin_site.root_path,
            "app_label": app_label,
            "action_form": action_form,
            "actions_on_top": self.actions_on_top,
            "actions_on_bottom": self.actions_on_bottom,
            "actions_selection_counter": self.actions_selection_counter,
            "orders_total": round_decimal(val=orders_total, places=2, roundfactor="0.001", normalize=True),
        }
        context.update(extra_context or {})
        context_instance = template.RequestContext(request, current_app=self.admin_site.name)
        return render_to_response("admin/orders/change_list.html", context, context_instance=context_instance)
Beispiel #28
0
def add(request, id=0, redirect_to='satchmo_cart'):
    """Add an item to the cart."""
    log.debug('FORM: %s', request.POST)
    formdata = request.POST.copy()
    productslug = None

    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')

    if 'productname' in formdata:
        productslug = formdata['productname']
    try:
        product, details = product_from_post(productslug, formdata)

        if not (product and product.active):
            log.debug("product %s is not active" % productslug)
            return bad_or_missing(request, _("That product is not available at the moment."))
        else:
            log.debug("product %s is active" % productslug)

    except (Product.DoesNotExist, MultiValueDictKeyError):
        log.debug("Could not find product: %s", productslug)
        return bad_or_missing(request, _('The product you have requested does not exist.'))

    # First we validate that the number isn't too big.
    if decimal_too_big(formdata['quantity']):
        return _product_error(request, product, _("Please enter a smaller number."))

    # Then we validate that we can round it appropriately.
    try:
        quantity = round_decimal(formdata['quantity'], places=cartplaces, roundfactor=roundfactor)
    except RoundedDecimalError:
        return _product_error(request, product,
            _("Invalid quantity."))

    if quantity <= Decimal('0'):
        return _product_error(request, product,
            _("Please enter a positive number."))

    cart = Cart.objects.from_request(request, create=True)
    # send a signal so that listeners can update product details before we add it to the cart.
    satchmo_cart_details_query.send(
            cart,
            product=product,
            quantity=quantity,
            details=details,
            request=request,
            form=formdata
            )
    try:
        added_item = cart.add_item(product, number_added=quantity, details=details)

    except CartAddProhibited as cap:
        return _product_error(request, product, cap.message)

    # got to here with no error, now send a signal so that listeners can also operate on this form.
    satchmo_cart_add_complete.send(cart, cart=cart, cartitem=added_item, product=product, request=request, form=formdata)
    satchmo_cart_changed.send(cart, cart=cart, request=request)

    if request.is_ajax():
        data = {
            'id': product.id,
            'name': product.translated_name(),
            'item_id': added_item.id,
            'item_qty': str(round_decimal(quantity, 2)),
            'item_price': six.text_type(moneyfmt(added_item.line_total)) or "0.00",
            'cart_count': str(round_decimal(cart.numItems, 2)),
            'cart_total': six.text_type(moneyfmt(cart.total)),
            # Legacy result, for now
            'results': _("Success"),
        }
        log.debug('CART AJAX: %s', data)

        return _json_response(data)
    else:
        url = reverse(redirect_to)
        return HttpResponseRedirect(url)
Beispiel #29
0
    try:
        cartitem = CartItem.objects.get(pk=itemid, cart=cart)
    except CartItem.DoesNotExist:
        return (False, cart, None, _("No such item in your cart."))

    if qty == Decimal('0'):
        cartitem.delete()
        cartitem = NullCartItem(itemid)
    else:
        if config_value('PRODUCT','NO_STOCK_CHECKOUT') == False:
            stock = cartitem.product.items_in_stock
            log.debug('checking stock quantity.  Have %d, need %d', stock, qty)
            if stock < qty:
                return (False, cart, cartitem, _("Unfortunately we only have %(stock)d '%(cartitem_name)s' in stock.") % {'stock': stock, 'cartitem_name': cartitem.product.translated_name()})

        cartitem.quantity = round_decimal(qty, places=cartplaces)
        cartitem.save()

    satchmo_cart_changed.send(cart, cart=cart, request=request)
    return (True, cart, cartitem, "")

def display(request, cart=None, error_message='', default_view_tax=None):
    """Display the items in the cart."""

    if default_view_tax is None:
        default_view_tax = config_value('TAX', 'DEFAULT_VIEW_TAX')

    if not cart:
        cart = Cart.objects.from_request(request)

    if cart.numItems > 0:
Beispiel #30
0
    try:
        cartitem = CartItem.objects.get(pk=itemid, cart=cart)
    except CartItem.DoesNotExist:
        return (False, cart, None, _("No such item in your cart."))

    if qty == Decimal('0'):
        cartitem.delete()
        cartitem = NullCartItem(itemid)
    else:
        if config_value('PRODUCT','NO_STOCK_CHECKOUT') == False:
            stock = cartitem.product.items_in_stock
            log.debug('checking stock quantity.  Have %d, need %d', stock, qty)
            if stock < qty:
                return (False, cart, cartitem, _("Unfortunately we only have %(stock)d '%(cartitem_name)s' in stock.") % {'stock': stock, 'cartitem_name': cartitem.product.translated_name()})

        cartitem.quantity = round_decimal(qty, places=cartplaces)
        cartitem.save()

    satchmo_cart_changed.send(cart, cart=cart, request=request)
    return (True, cart, cartitem, "")

def display(request, cart=None, error_message='', default_view_tax=None):
    """Display the items in the cart."""

    if default_view_tax is None:
        default_view_tax = config_value('TAX', 'DEFAULT_VIEW_TAX')

    if not cart:
        cart = Cart.objects.from_request(request)

    if cart.numItems > 0:
Beispiel #31
0
def productvariation_details(product, include_tax, user, create=False):
    """Build the product variation details, for conversion to javascript.

    Returns variation detail dictionary built like so:
    details = {
        "OPTION_KEY" : {
            "SLUG": "Variation Slug",
            "PRICE" : {"qty" : "$price", [...]},
            "SALE" : {"qty" : "$price", [...]},
            "TAXED" : "$taxed price",   # omitted if no taxed price requested
            "QTY" : 1
        },
        [...]
    }
    """

    ignore_stock = config_value('PRODUCT','NO_STOCK_CHECKOUT')
    discount = find_best_auto_discount(product)
    use_discount = discount and discount.percentage > 0

    if include_tax:
        from tax.utils import get_tax_processor
        taxer = get_tax_processor(user=user)
        tax_class = product.taxClass

    details = {'SALE' : use_discount}

    variations = ProductPriceLookup.objects.filter(parentid=product.id).order_by("-price")
    if variations.count() == 0:
        if create:
            log.debug('Creating price lookup for %s', product)
            ProductPriceLookup.objects.smart_create_for_product(product)
            variations = ProductPriceLookup.objects.filter(parentid=product.id).order_by("-price")
        else:
            log.warning('You must run satchmo_rebuild_pricing and add it to a cron-job to run every day, or else the product details will not work for product detail pages.')
    for detl in variations:
        key = detl.key
        if details.has_key(key):
            detail = details[key]
            qty = detl.quantity
        else:
            detail = {}
            detail['SLUG'] = detl.productslug

            if not detl.active:
                qty = round_decimal('-1.0')
            elif ignore_stock:
                qty = round_decimal('10000.0')
            else:
                qty = round_decimal(detl.items_in_stock)

            detail['QTY'] = round_decimal(qty)

            detail['PRICE'] = {}

            if use_discount:
                detail['SALE'] = {}

            if include_tax:
                detail['TAXED'] = {}
                if use_discount:
                    detail['TAXED_SALE'] = {}

	    if detl.productimage_set:
	            detail['ADDITIONAL_IMAGES'] = [u"%s" % prodimg.picture for prodimg in detl.productimage_set.all()]

            details[key] = detail

        qtykey = "%d" % detl.quantity

        price = detl.dynamic_price

        detail['PRICE'][qtykey] = moneyfmt(price)
        if use_discount:
            detail['SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(price, discount.percentage))

        if include_tax:
            tax_price = taxer.by_price(tax_class, price) + price
            detail['TAXED'][qtykey] = moneyfmt(tax_price)
            if use_discount:
                detail['TAXED_SALE'][qtykey] = moneyfmt(calc_discounted_by_percentage(tax_price, discount.percentage))

    return details
Beispiel #32
0
def add_ajax(request, id=0, template="shop/json.html"):
    cartplaces = config_value('SHOP', 'CART_PRECISION')
    roundfactor = config_value('SHOP', 'CART_ROUNDING')    
    
    data = {'errors': []}
    product = None
    formdata = request.POST.copy()
    if not formdata.has_key('productname'):
        data['errors'].append(('product', _('No product requested')))
    else:
        productslug = formdata['productname']
        log.debug('CART_AJAX: slug=%s', productslug)
        try:
            product, details = product_from_post(productslug, formdata)

        except Product.DoesNotExist:
            log.warn("Could not find product: %s", productslug)
            product = None

        if not product:
            data['errors'].append(('product', _('The product you have requested does not exist.')))

        else:
            if not product.active:
                data['errors'].append(('product', _('That product is not available at the moment.')))

            else:
                data['id'] = product.id
                data['name'] = product.translated_name()

                if not formdata.has_key('quantity'):
                    quantity = Decimal('-1')
                else:
                    quantity = formdata['quantity']

                try:
                    quantity = round_decimal(quantity, places=cartplaces, roundfactor=roundfactor)

                    if quantity < Decimal('0'):
                        data['errors'].append(('quantity', _('Choose a quantity.')))

                except RoundedDecimalError:
                    data['errors'].append(('quantity', _('Invalid quantity.')))

    tempCart = Cart.objects.from_request(request, create=True)

    if not data['errors']:
        # send a signal so that listeners can update product details before we add it to the cart.
        satchmo_cart_details_query.send(
                tempCart,
                product=product,
                quantity=quantity,
                details=details,
                request=request,
                form=formdata
                )
        try:
            added_item = tempCart.add_item(product, number_added=quantity)
            request.session['cart'] = tempCart.id
            data['results'] = _('Success')
            if added_item:
                # send a signal so that listeners can also operate on this form and item.
                satchmo_cart_add_complete.send(
                        tempCart,
                        cartitem=added_item,
                        product=product,
                        request=request,
                        form=formdata
                        )
                        
        except CartAddProhibited, cap:
            data['results'] = _('Error')
            data['errors'].append(('product', cap.message))
Beispiel #33
0
    except CartItem.DoesNotExist:
        return (False, cart, None, _("No such item in your cart."))

    if qty == Decimal('0'):
        cartitem.delete()
        cartitem = NullCartItem(itemid)
    else:
        from satchmo_store.shop.models import Config
        config = Config.objects.get_current()
        if config_value('PRODUCT','NO_STOCK_CHECKOUT') == False:
            stock = cartitem.product.items_in_stock
            log.debug('checking stock quantity.  Have %d, need %d', stock, qty)
            if stock < qty:
                return (False, cart, cartitem, _("Not enough items of '%s' in stock.") % cartitem.product.translated_name())

        cartitem.quantity = round_decimal(qty, places=cartplaces)
        cartitem.save()

    satchmo_cart_changed.send(cart, cart=cart, request=request)
    return (True, cart, cartitem, "")

def display(request, cart=None, error_message='', default_view_tax=NOTSET):
    """Display the items in the cart."""

    if default_view_tax == NOTSET:
        default_view_tax = config_value('TAX', 'DEFAULT_VIEW_TAX')

    if not cart:
        cart = Cart.objects.from_request(request)

    if cart.numItems > 0:
Beispiel #34
0
    try:
        cartitem = CartItem.objects.get(pk=itemid, cart=cart)
    except CartItem.DoesNotExist:
        return (False, cart, None, _("No such item in your cart."))

    if qty == Decimal('0'):
        cartitem.delete()
        cartitem = NullCartItem(itemid)
    else:
        if config_value('PRODUCT','NO_STOCK_CHECKOUT') == False:
            stock = cartitem.product.items_in_stock
            log.debug('checking stock quantity.  Have %d, need %d', stock, qty)
            if stock < qty:
                return (False, cart, cartitem, _("Not enough items of '%s' in stock.") % cartitem.product.translated_name())

        cartitem.quantity = round_decimal(qty, places=cartplaces)
        cartitem.save()

    satchmo_cart_changed.send(cart, cart=cart, request=request)
    return (True, cart, cartitem, "")

def display(request, cart=None, error_message='', default_view_tax=None):
    """Display the items in the cart."""

    if default_view_tax is None:
        default_view_tax = config_value('TAX', 'DEFAULT_VIEW_TAX')

    if not cart:
        cart = Cart.objects.from_request(request)

    if cart.numItems > 0: