def render(self, context): try: show_tax = self.show_tax.resolve(context) except template.VariableDoesNotExist: show_tax = self.raw_tax if show_tax: tag = CartitemLineTaxedTotalNode(self.raw_cartitem, self.raw_currency) return tag.render(context) try: cartitem = self.cartitem.resolve(context) except template.VariableDoesNotExist: log.warn("Could not resolve template variable: %s", self.cartitem) return "" try: show_currency = self.show_currency.resolve(context) except template.VariableDoesNotExist: show_currency = self.raw_currency if show_currency: request = context.get("request") currency_code = currency_for_request(request) return money_format(cartitem.line_total, currency_code) else: return cartitem.line_total
def test_geoip__no_ip(self, mock_get_real_ip): mock_get_real_ip.return_value = None request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def get(self, request, *args, **kwargs): """ Return the currency for the request. """ currency_code = currency_for_request(request) currency = Currency.objects.all_accepted().get(iso_4217_code=currency_code) serializer = CurrencySerializer(currency) return Response(serializer.data)
def _get_shipping_choices(request, paymentmodule, cart, contact, default_view_tax=False): """Iterate through legal shipping modules, building the list for display to the user. Returns the shipping choices list, along with a dictionary of shipping choices, useful for building javascript that operates on shipping choices. """ shipping_options = [] shipping_dict = {} if not cart.is_shippable: methods = [shipping_method_by_key("NoShipping")] else: methods = shipping_methods() valid_methods = [] for method in methods: method.calculate(cart, contact) if method.valid(): valid_methods.append((method, method.cost())) # sort methods by cost valid_methods.sort(key=lambda method_cost: int(method_cost[1])) for method, shipcost in valid_methods: template = lookup_template(paymentmodule, "shipping_options.html") t = loader.get_template(template) shipping_tax = None taxed_shipping_price = None if config_value("TAX", "TAX_SHIPPING"): shipping_tax = config_value("TAX", "TAX_CLASS") taxer = _get_taxprocessor(request) total = shipcost + taxer.by_price(shipping_tax, shipcost) currency_code = currency_for_request(request) taxed_shipping_price = money_format(total, currency_code) data = { "amount": shipcost, "description": method.description(), "method": method.method(), "expected_delivery": method.expectedDelivery(), "default_view_tax": default_view_tax, "shipping_tax": shipping_tax, "taxed_shipping_price": taxed_shipping_price, } if hasattr(method, "shipping_discount"): data["discount"] = method.shipping_discount() shipping_options.append((method.id, t.render(data))) shipping_dict[method.id] = shipcost return shipping_options, shipping_dict
def get(self, request, *args, **kwargs): """ Return the currency for the request. """ currency_code = currency_for_request(request) currency = Currency.objects.all_accepted().get( iso_4217_code=currency_code) serializer = CurrencySerializer(currency) return Response(serializer.data)
def _get_shipping_choices( request, paymentmodule, cart, contact, default_view_tax=False ): """Iterate through legal shipping modules, building the list for display to the user. Returns the shipping choices list, along with a dictionary of shipping choices, useful for building javascript that operates on shipping choices. """ shipping_options = [] shipping_dict = {} if not cart.is_shippable: methods = [shipping_method_by_key("NoShipping")] else: methods = shipping_methods() valid_methods = [] for method in methods: method.calculate(cart, contact) if method.valid(): valid_methods.append((method, method.cost())) # sort methods by cost valid_methods.sort(key=lambda method_cost: int(method_cost[1])) for method, shipcost in valid_methods: template = lookup_template(paymentmodule, "shipping_options.html") t = loader.get_template(template) shipping_tax = None taxed_shipping_price = None if config_value("TAX", "TAX_SHIPPING"): shipping_tax = config_value("TAX", "TAX_CLASS") taxer = _get_taxprocessor(request) total = shipcost + taxer.by_price(shipping_tax, shipcost) currency_code = currency_for_request(request) taxed_shipping_price = money_format(total, currency_code) data = { "amount": shipcost, "description": method.description(), "method": method.method(), "expected_delivery": method.expectedDelivery(), "default_view_tax": default_view_tax, "shipping_tax": shipping_tax, "taxed_shipping_price": taxed_shipping_price, } if hasattr(method, "shipping_discount"): data["discount"] = method.shipping_discount() shipping_options.append((method.id, t.render(data))) shipping_dict[method.id] = shipcost return shipping_options, shipping_dict
def full_product(context, product): """ Renders a product in a way that is useful for the product detail page """ context["product"] = product current_currency = currency_for_request(context.get("request")) context["other_prices"] = [ money_format( convert_to_currency(product.unit_price, currency.iso_4217_code), currency.iso_4217_code, ) for currency in Currency.objects.filter(accepted=True).exclude( iso_4217_code=current_currency).order_by("iso_4217_code") ] return context
def test_geoip__no_country(self, mock_get_real_ip, mock_geoip): mock_get_real_ip.return_value = "127.0.0.1" class MockGeoIP(object): def country(self, ip): return {"country_name": None, "country_code": None} mock_geoip.return_value = MockGeoIP() request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def discount_saved(context, product, discount): """Returns the amount saved by the discount""" request = context.get("request") currency = currency_for_request(request) if discount and discount.valid_for_product(product): unit_price = convert_to_currency(product.unit_price, currency) discounted = calc_by_percentage(unit_price, discount.percentage) saved = unit_price - discounted cents = Decimal("0.01") price = saved.quantize(cents) else: price = Decimal("0.00") return money_format(price, currency)
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 if "quantity" in reqdata: quantity = int(reqdata["quantity"]) else: quantity = 1 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) base_tax = get_tax(request.user, product, quantity) price_with_tax = price + base_tax currency_code = currency_for_request(request) results["slug"] = product.slug results["currency_price"] = money_format(price, currency_code) results["price"] = float(price) results["tax"] = float(base_tax) results["currency_tax"] = money_format(base_tax, currency_code) results["currency_price_with_tax"] = money_format( price_with_tax, currency_code ) results["price_with_tax"] = float(price_with_tax) 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")
def render(self, context): taxer = _get_taxprocessor(context["request"]) try: item = template.resolve_variable(self.cartitem, context) except template.VariableDoesNotExist: raise template.TemplateSyntaxError("No such variable: %s", self.cartitem) total = item.line_total + taxer.by_price(item.product.taxClass, item.line_total) if self.currency: request = context.get("request") currency_code = currency_for_request(request) return money_format(total, currency_code) return total
def test_geoip__country_doesnt_match_accepted_country( self, mock_get_real_ip, mock_geoip): mock_get_real_ip.return_value = "163.44.191.38" class MockGeoIP(object): def country(self, ip): return {"country_name": "Japan", "country_code": "JP"} mock_geoip.return_value = MockGeoIP() request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def isValid(self, cart=None, request=None): """ Make sure this discount still has available uses and is in the current date range. If a cart has been populated, validate that it does apply to the products we have selected. """ if not self.active: return (False, ugettext("This coupon is disabled.")) if self.startDate > datetime.date.today(): return (False, ugettext("This coupon is not active yet.")) if self.endDate < datetime.date.today(): return (False, ugettext("This coupon has expired.")) if self.numUses > self.allowedUses: return ( False, ugettext( "This discount has exceeded the number of allowed uses."), ) if not cart: return (True, ugettext("Valid.")) minOrder = self.minOrder or 0 if cart.total < minOrder: currency_code = currency_for_request(request) return ( False, ugettext( "This discount only applies to orders of at least %s." % money_format(minOrder, currency_code)), ) validItems = False validproducts = self._get_valid_product_dict() if validproducts: for cart_item in cart.cartitem_set.all(): if cart_item.product.id in validproducts: validItems = True break # Once we have 1 valid item, we exit else: validItems = True if validItems: return (True, ugettext("Valid.")) else: return ( False, ugettext( "This discount cannot be applied to the products in your cart." ), )
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.active().get(slug=product_slug) found = True if "quantity" in reqdata: quantity = int(reqdata["quantity"]) else: quantity = 1 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) base_tax = get_tax(request.user, product, quantity) price_with_tax = price + base_tax currency_code = currency_for_request(request) results["slug"] = product.slug results["currency_price"] = money_format(price, currency_code) results["price"] = float(price) results["tax"] = float(base_tax) results["currency_tax"] = money_format(base_tax, currency_code) results["currency_price_with_tax"] = money_format( price_with_tax, currency_code) results["price_with_tax"] = float(price_with_tax) 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")
def isValid(self, cart=None, request=None): """ Make sure this discount still has available uses and is in the current date range. If a cart has been populated, validate that it does apply to the products we have selected. """ if not self.active: return (False, ugettext("This coupon is disabled.")) if self.startDate > datetime.date.today(): return (False, ugettext("This coupon is not active yet.")) if self.endDate < datetime.date.today(): return (False, ugettext("This coupon has expired.")) if self.numUses > self.allowedUses: return ( False, ugettext("This discount has exceeded the number of allowed uses."), ) if not cart: return (True, ugettext("Valid.")) minOrder = self.minOrder or 0 if cart.total < minOrder: currency_code = currency_for_request(request) return ( False, ugettext( "This discount only applies to orders of at least %s." % money_format(minOrder, currency_code) ), ) validItems = False validproducts = self._get_valid_product_dict() if validproducts: for cart_item in cart.cartitem_set.all(): if cart_item.product.id in validproducts: validItems = True break # Once we have 1 valid item, we exit else: validItems = True if validItems: return (True, ugettext("Valid.")) else: return ( False, ugettext( "This discount cannot be applied to the products in your cart." ), )
def discount_price(context, product, discount): """Returns the product price with the discount applied. Ex: {% discount_price product sale %} """ request = context.get("request") currency = currency_for_request(request) unit_price = convert_to_currency(product.unit_price, currency) if discount and discount.valid_for_product(product): price = calc_by_percentage(unit_price, discount.percentage) else: price = unit_price return money_format(price, currency)
def test_geoip__country_doesnt_match_accepted_country( self, mock_get_real_ip, mock_geoip ): mock_get_real_ip.return_value = "163.44.191.38" class MockGeoIP(object): def country(self, ip): return {"country_name": "Japan", "country_code": "JP"} mock_geoip.return_value = MockGeoIP() request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def render(self, context): taxer = _get_taxprocessor(context["request"]) try: price = template.resolve_variable(self.price, context) except template.VariableDoesNotExist: raise template.TemplateSyntaxError("No such variable: %s", self.price) total = price + taxer.by_price(self.taxclass, price) if self.currency: request = context.get("request") currency_code = currency_for_request(request) return money_format(total, currency_code) return total
def option_total_price(context, product, option_item): """ Returns the price as (+$1.00) or (-$1.00) depending on the sign of the price change The currency format is base upon locale """ if option_item.price_change: val = product.unit_price + option_item.price_change else: val = product.unit_price request = context.get("request") currency_code = currency_for_request(request) return money_format(val, currency_code)
def test_geoip__country_matches_accepted_country(self, mock_get_real_ip, mock_geoip): mock_get_real_ip.return_value = "88.97.34.8" gbp = GBPCurrencyFactory() gbp.accepted = True gbp.save() class MockGeoIP(object): def country(self, ip): return {"country_name": "United Kingdom", "country_code": "GB"} mock_geoip.return_value = MockGeoIP() request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "GBP")
def option_price(context, option_item): """ Returns the price as (+$1.00) or (-$1.00) depending on the sign of the price change The currency format is base upon locale """ output = "" if option_item.price_change != 0: request = context.get("request") currency_code = currency_for_request(request) amount = money_format(abs(option_item.price_change), currency_code) if option_item.price_change < 0: output = "(- %s)" % amount elif option_item.price_change > 0: output = "(+ %s)" % amount return output
def test_geoip__country_matches_accepted_country( self, mock_get_real_ip, mock_geoip ): mock_get_real_ip.return_value = "88.97.34.8" gbp = GBPCurrencyFactory() gbp.accepted = True gbp.save() class MockGeoIP(object): def country(self, ip): return {"country_name": "United Kingdom", "country_code": "GB"} mock_geoip.return_value = MockGeoIP() request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "GBP")
def currency(context, value, currency_code=None): """Convert a value to a money formatted string. If a currency is not supplied, one will selected based on the request. Usage: {% currency val %} """ if value == "" or value is None: return value if currency_code is None: request = context.get("request") currency_code = currency_for_request(request) value = convert_to_currency(value, currency_code) return mark_safe(money_format(value, currency_code))
def get_price(request, product_slug): """Get base price for a product, returning the answer encoded as JSON.""" quantity = 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 "quantity" in request.POST: quantity = int(request.POST["quantity"]) currency_code = currency_for_request(request) 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 = money_format(pvp.get_qty_price(quantity), currency_code) else: price = money_format(product.get_qty_price(quantity), currency_code) if not price: return http.HttpResponse( json_encode(("", _("not available"))), mimetype="text/javascript" ) return http.HttpResponse( json_encode((prod_slug, price)), mimetype="text/javascript" )
def get_or_create_order(request, working_cart, contact, data): """Get the existing order from the session, else create using the working_cart, contact and data""" shipping = data["shipping"] discount = data["discount"] try: newOrder = Order.objects.from_request(request) pay_ship_save( newOrder, working_cart, contact, shipping=shipping, discount=discount, update=True, ) except Order.DoesNotExist: # Get currency from request iso_4217_code = currency_for_request(request) currency = Currency.objects.all_accepted().get( iso_4217_code=iso_4217_code) try: exchange_rate = currency.exchange_rates.latest().rate except ExchangeRate.DoesNotExist: exchange_rate = Decimal("1.00") # Create a new order. newOrder = Order(contact=contact, currency=currency, exchange_rate=exchange_rate) pay_ship_save(newOrder, working_cart, contact, shipping=shipping, discount=discount) request.session["orderID"] = newOrder.id return newOrder
def get_or_create_order(request, working_cart, contact, data): """Get the existing order from the session, else create using the working_cart, contact and data""" shipping = data["shipping"] discount = data["discount"] try: newOrder = Order.objects.from_request(request) pay_ship_save( newOrder, working_cart, contact, shipping=shipping, discount=discount, update=True, ) except Order.DoesNotExist: # Get currency from request iso_4217_code = currency_for_request(request) currency = Currency.objects.all_accepted().get(iso_4217_code=iso_4217_code) try: exchange_rate = currency.exchange_rates.latest().rate except ExchangeRate.DoesNotExist: exchange_rate = Decimal("1.00") # Create a new order. newOrder = Order( contact=contact, currency=currency, exchange_rate=exchange_rate ) pay_ship_save( newOrder, working_cart, contact, shipping=shipping, discount=discount ) request.session["orderID"] = newOrder.id return newOrder
def get_price(request, product_slug): """Get base price for a product, returning the answer encoded as JSON.""" quantity = 1 try: product = Product.objects.active().get(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 "quantity" in request.POST: quantity = int(request.POST["quantity"]) currency_code = currency_for_request(request) 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 = money_format(pvp.get_qty_price(quantity), currency_code) else: price = money_format(product.get_qty_price(quantity), currency_code) if not price: return http.HttpResponse(json_encode(("", _("not available"))), mimetype="text/javascript") return http.HttpResponse(json_encode((prod_slug, price)), mimetype="text/javascript")
def test_fallback_to_primary(self): request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def productvariation_details(product, include_tax, user, request, 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", [...]}, "TAXED" : "$taxed price", # omitted if no taxed price requested "QTY" : 1 }, [...] } """ config = Config.objects.get_current() ignore_stock = config.no_stock_checkout if include_tax: taxer = get_taxprocessor(user) tax_class = product.taxClass details = {} variations = ProductPriceLookup.objects.filter(parentid=product.id) 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) 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 key in details: detail = details[key] else: detail = {} detail["SLUG"] = detl.productslug if not detl.active: qty = -1 elif ignore_stock: qty = 10000 else: qty = detl.items_in_stock detail["QTY"] = qty detail["PRICE"] = {} if include_tax: detail["TAXED"] = {} details[key] = detail price = detl.dynamic_price currency_code = currency_for_request(request) detail["PRICE"][detl.quantity] = money_format(price, currency_code) if include_tax: tax_price = taxer.by_price(tax_class, price) + price detail["TAXED"][detl.quantity] = money_format(tax_price, currency_code) return details
def test_geoip__not_set_up(self): request = self.request_factory.get("/") request.session = {} self.assertEqual(currency_for_request(request), "EUR")
def test_currency_code_in_session(self): GBPCurrencyFactory() request = self.request_factory.get("/") request.session = {"currency_code": "GBP"} self.assertEqual(currency_for_request(request), "GBP")
def test_no_request(self): self.assertEqual(currency_for_request(None), "EUR")
def productvariation_details(product, include_tax, user, request, 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", [...]}, "TAXED" : "$taxed price", # omitted if no taxed price requested "QTY" : 1 }, [...] } """ config = Config.objects.get_current() ignore_stock = config.no_stock_checkout if include_tax: taxer = get_taxprocessor(user) tax_class = product.taxClass details = {} variations = ProductPriceLookup.objects.filter(parentid=product.id) 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) 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 key in details: detail = details[key] else: detail = {} detail["SLUG"] = detl.productslug if not detl.active: qty = -1 elif ignore_stock: qty = 10000 else: qty = detl.items_in_stock detail["QTY"] = qty detail["PRICE"] = {} if include_tax: detail["TAXED"] = {} details[key] = detail price = detl.dynamic_price currency_code = currency_for_request(request) detail["PRICE"][detl.quantity] = money_format(price, currency_code) if include_tax: tax_price = taxer.by_price(tax_class, price) + price detail["TAXED"][detl.quantity] = money_format( tax_price, currency_code) return details