def test_get_price(self): """ Get a price/productname for a ProductVariation """ response = self.client.get(prefix + '/product/DJ-Rocks/') self.assertContains(response, "Django Rocks shirt", count=1, status_code=200) # this tests the unmolested price from the ConfigurableProduct, and # makes sure we get a good productname back for the ProductVariation response = self.client.post(prefix + '/product/DJ-Rocks/prices/', { "1": "S", "2": "B", "quantity": 1 }) self.assertEquals( response.content, '["DJ-Rocks_S_B", "%s20.00"]' % config_value('SHOP', 'CURRENCY')) # This tests the option price_change feature, and again the productname response = self.client.post(prefix + '/product/DJ-Rocks/prices/', { "1": "L", "2": "BL", "quantity": 2 }) self.assertEquals( response.content, '["DJ-Rocks_L_BL", "%s23.00"]' % config_value('SHOP', 'CURRENCY'))
def check_with_akismet(comment=None, request=None, **kwargs): if config_value("PRODUCT", "AKISMET_ENABLE"): key = config_value("PRODUCT", "AKISMET_KEY") if key: site = Site.objects.get_current() shop = urlresolvers.reverse('satchmo_shop_home') from akismet import Akismet akismet = Akismet( key=settings.AKISMET_API_KEY, blog_url='http://%s' % url_join(site.domain, shop)) if akismet.verify_key(): akismet_data = { 'comment_type': 'comment', 'referrer': request.META.get('HTTP_REFERER', ""), 'user_ip': comment.ip_address, 'user_agent': '' } if akismet_api.comment_check(smart_str(comment.comment), data=akismet_data, build_data=True): comment.is_public=False comment.save() log.info("Akismet marked comment #%i as spam", comment.id) else: log.debug("Akismet accepted comment #%i", comment.id) else: log.warn("Akismet key '%s' not accepted by akismet service.", key) else: log.info("Akismet enabled, but no key found. Please put in your admin settings.")
def process(self, order=None): """ Calculate the tax and return it """ if order: self.order = order else: order = self.order percent = config_value("TAX", "PERCENT") sub_total = Decimal("0.00") for item in order.orderitem_set.filter(product__taxable=True): sub_total += item.sub_total itemtax = sub_total * (percent / 100) taxrates = {"%i%%" % percent: itemtax} if config_value("TAX", "TAX_SHIPPING"): shipping = order.shipping_sub_total sub_total += shipping ship_tax = shipping * (percent / 100) taxrates["Shipping"] = ship_tax tax = sub_total * (percent / 100) return tax, taxrates
def process(self, order=None): """ Calculate the tax and return it """ if order: self.order = order else: order = self.order percent = config_value('TAX', 'PERCENT') sub_total = Decimal("0.00") for item in order.orderitem_set.filter(product__taxable=True): sub_total += item.sub_total itemtax = sub_total * (percent / 100) taxrates = {'%i%%' % percent: itemtax} if config_value('TAX', 'TAX_SHIPPING'): shipping = order.shipping_sub_total sub_total += shipping ship_tax = shipping * (percent / 100) taxrates['Shipping'] = ship_tax tax = sub_total * (percent / 100) return tax, taxrates
def order_payload(order): data = {} data["api_key"] = config_value("satchmo.fulfilment.modules.six", "API_KEY") data["test"] = config_value("satchmo.fulfilment.modules.six", "TEST_MODE") data["allow_preorder"] = config_value("satchmo.fulfilment.modules.six", "ALLOW_PREORDER") data["update_stock"] = config_value("satchmo.fulfilment.modules.six", "UPDATE_STOCK") data["order"] = {} despatch_url = external_url(reverse("six_despatch", kwargs={"order_id": order.id, "verification_hash": order.verification_hash})) data["order"]["client_ref"] = order.id data["order"]["po_number"] = order.id data["order"]["date_placed"] = unicode(order.time_stamp) data["order"]["callback_url"] = despatch_url data["order"]["postage_speed"] = order.shipping_postage_speed data["order"]["postage_cost"] = float_price(order.shipping_cost) data["order"]["total_amount"] = float_price(order.sub_total) data["order"]["signed_for"] = order.shipping_signed_for data["order"]["tracked"] = order.shipping_tracked data["order"]["ShippingContact"] = { "dear": order.contact.user.first_name, "name": order.ship_addressee, "email": order.contact.user.email, "phone": get_phone_number(order), "address": order.ship_street1, "address_contd": order.ship_street2, "city": order.ship_city, "county": order.ship_state, "country": unicode(order.ship_country), "postcode": order.ship_postal_code, } data["order"]["BillingContact"] = { "name": order.bill_addressee, "email": order.contact.user.email, "phone": get_phone_number(order), "address": order.bill_street1, "address_contd": order.bill_street2, "city": order.bill_city, "county": order.bill_state, "country": unicode(order.bill_country), "postcode": order.bill_postal_code, } data["order"]["items"] = [ { # Six limits slugs to 40 characters. Six stores # client_refs with a length of 40 characters (truncated # silently). When passing a > 40 character slug, the # whole slug is checked against the 40 character # client_ref and doesn't match. So, we just truncate # slugs to 40 characters. "client_ref": item.product.slug[:40], "quantity": item.quantity, "price": float_price(item.unit_price), } for item in order.orderitem_set.all() ] return json.dumps(data)
def make_urlpatterns(): patterns = [] for key in config_value('PAYMENT', 'MODULES'): cfg = config_get(key, 'MODULE') modulename = cfg.editor_value urlmodule = "%s.urls" % modulename patterns.append(url(config_value(key, 'URL_BASE'), [urlmodule, modulename, ''])) return tuple(patterns)
def make_urlpatterns(): patterns = [] for key in config_value('PAYMENT', 'MODULES'): cfg = config_get(key, 'MODULE') modulename = cfg.editor_value urlmodule = "%s.urls" % modulename patterns.append(url(config_value(key, 'URL_BASE'), [urlmodule])) return tuple(patterns)
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) taxed_shipping_price = money_format(total) 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() c = RequestContext(request, data) shipping_options.append((method.id, t.render(c))) shipping_dict[method.id] = shipcost return shipping_options, shipping_dict
def test_custom_product(self): """ Verify that the custom product is working as expected. """ pm = config_get("PRODUCT", "PRODUCT_TYPES") pm.update( [ "product::ConfigurableProduct", "product::ProductVariation", "product::CustomProduct", "product::SubscriptionProduct", ] ) response = self.client.get(prefix + "/") self.assertContains(response, "Computer", count=1) response = self.client.get(prefix + "/product/satchmo-computer/") self.assertContains(response, "Memory", count=1) self.assertContains(response, "Case", count=1) self.assertContains(response, "Monogram", count=1) response = self.client.post( prefix + "/cart/add/", {"productname": "satchmo-computer", "5": "1.5gb", "6": "mid", "custom_monogram": "CBM", "quantity": 1}, ) self.assertRedirects(response, prefix + "/cart/", status_code=302, target_status_code=200) response = self.client.get(prefix + "/cart/") self.assertContains(response, '/satchmo-computer/">satchmo computer', count=1, status_code=200) self.assertContains(response, smart_str("%s168.00" % config_value("SHOP", "CURRENCY")), count=3) self.assertContains(response, smart_str("Monogram: CBM %s10.00" % config_value("SHOP", "CURRENCY")), count=1) self.assertContains( response, smart_str("Case - External Case: Mid %s10.00" % config_value("SHOP", "CURRENCY")), count=1 ) self.assertContains( response, smart_str("Memory - Internal RAM: 1.5 GB %s25.00" % config_value("SHOP", "CURRENCY")), count=1 ) response = self.client.post(url("satchmo_checkout-step1"), get_step1_post_data(self.US)) self.assertRedirects(response, url("DUMMY_satchmo_checkout-step2"), status_code=302, target_status_code=200) data = { "credit_type": "Visa", "credit_number": "4485079141095836", "month_expires": "1", "year_expires": "2012", "ccv": "552", "shipping": "FlatRate", } response = self.client.post(url("DUMMY_satchmo_checkout-step2"), data) self.assertRedirects(response, url("DUMMY_satchmo_checkout-step3"), status_code=302, target_status_code=200) response = self.client.get(url("DUMMY_satchmo_checkout-step3")) self.assertContains( response, smart_str("satchmo computer - %s168.00" % config_value("SHOP", "CURRENCY")), count=1, status_code=200, ) response = self.client.post(url("DUMMY_satchmo_checkout-step3"), {"process": "True"}) self.assertRedirects(response, url("DUMMY_satchmo_checkout-success"), status_code=302, target_status_code=200) self.assertEqual(len(mail.outbox), 1)
def process(self): """ Calculate the tax and return it """ subtotal = self.order.sub_total - self.order.discount if config_value('TAX', 'TAX_SHIPPING'): subtotal += self.order.shipping_cost percent = config_value('TAX', 'PERCENT') return subtotal * (percent / 100)
def process(self): """ Calculate the tax and return it """ subtotal = self.order.sub_total - self.order.discount if config_value('TAX','TAX_SHIPPING'): subtotal += self.order.shipping_cost percent = config_value('TAX','PERCENT') return subtotal * (percent/100)
def display_featured(): """ Used by the index generic view to choose how the featured products are displayed. Items can be displayed randomly or all in order """ random_display = config_value('SHOP','RANDOM_FEATURED') num_to_display = config_value('SHOP','NUM_DISPLAY') q = Product.objects.featured_by_site() if not random_display: return q[:num_to_display] else: return q.order_by('?')[:num_to_display]
def test_checkout(self): """ Run through a full checkout process """ cache_delete() tax = config_get("TAX", "MODULE") tax.update("satchmo.tax.modules.percent") pcnt = config_get("TAX", "PERCENT") pcnt.update("10") shp = config_get("TAX", "TAX_SHIPPING") shp.update(False) self.test_cart_adding() response = self.client.post(url("satchmo_checkout-step1"), get_step1_post_data(self.US)) self.assertRedirects(response, url("DUMMY_satchmo_checkout-step2"), status_code=302, target_status_code=200) data = { "credit_type": "Visa", "credit_number": "4485079141095836", "month_expires": "1", "year_expires": "2009", "ccv": "552", "shipping": "FlatRate", } response = self.client.post(url("DUMMY_satchmo_checkout-step2"), data) self.assertRedirects(response, url("DUMMY_satchmo_checkout-step3"), status_code=302, target_status_code=200) response = self.client.get(url("DUMMY_satchmo_checkout-step3")) self.assertContains( response, smart_str("Shipping + %s4.00" % config_value("SHOP", "CURRENCY")), count=1, status_code=200 ) self.assertContains( response, smart_str("Tax + %s4.60" % config_value("SHOP", "CURRENCY")), count=1, status_code=200 ) self.assertContains( response, smart_str("Total = %s54.60" % config_value("SHOP", "CURRENCY")), count=1, status_code=200 ) response = self.client.post(url("DUMMY_satchmo_checkout-step3"), {"process": "True"}) self.assertRedirects(response, url("DUMMY_satchmo_checkout-success"), status_code=302, target_status_code=200) self.assertEqual(len(mail.outbox), 1) # Log in as a superuser user = User.objects.create_user("fredsu", "*****@*****.**", "passwd") user.is_staff = True user.is_superuser = True user.save() self.client.login(username="******", password="******") # Test pdf generation response = self.client.get("/admin/print/invoice/1/") self.assertContains(response, "reportlab", status_code=200) response = self.client.get("/admin/print/packingslip/1/") self.assertContains(response, "reportlab", status_code=200) response = self.client.get("/admin/print/shippinglabel/1/") self.assertContains(response, "reportlab", status_code=200)
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) taxed_shipping_price = money_format(total) 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() c = RequestContext(request, data) shipping_options.append((method.id, t.render(c))) shipping_dict[method.id] = shipcost return shipping_options, shipping_dict
def shipping(self, subtotal=None): if subtotal is None and self.order: subtotal = self.order.shipping_sub_total if subtotal: subtotal = self.order.shipping_sub_total if config_value('TAX', 'TAX_SHIPPING'): percent = config_value('TAX', 'PERCENT') t = subtotal * (percent / 100) else: t = Decimal("0.00") else: t = Decimal("0.00") return t
def shipping(self, subtotal=None): if subtotal is None and self.order: subtotal = self.order.shipping_sub_total if subtotal: subtotal = self.order.shipping_sub_total if config_value("TAX", "TAX_SHIPPING"): percent = config_value("TAX", "PERCENT") t = subtotal * (percent / 100) else: t = Decimal("0.00") else: t = Decimal("0.00") return t
def _get_shipping_choices(paymentmodule, cart, contact): """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 = {} for module in config_value('SHIPPING','MODULES'): #Create the list of information the user will see shipping_module = load_module(module) shipping_instance = shipping_module.Calc(cart, contact) if shipping_instance.valid(): template = lookup_template(paymentmodule, 'shipping_options.html') t = loader.get_template(template) shipcost = shipping_instance.cost() c = Context({ 'amount': shipcost, 'description' : shipping_instance.description(), 'method' : shipping_instance.method(), 'expected_delivery' : shipping_instance.expectedDelivery() }) shipping_options.append((shipping_instance.id, t.render(c))) shipping_dict[shipping_instance.id] = shipcost return shipping_options, shipping_dict
def get_newsletter_module(): try: modulename = config_value('NEWSLETTER', 'MODULE') except AttributeError: modulename = 'satchmo.newsletter.ignore' return load_module(modulename)
def get_newsletter_module(): try: modulename = config_value("NEWSLETTER", "MODULE") except AttributeError: modulename = "satchmo.newsletter.ignore" return load_module(modulename)
def view_user_data_listener(contact=None, contact_dict=None, **kwargs): module = config_value("NEWSLETTER", "MODULE") if module not in ("", "satchmo.newsletter.ignore"): contact_dict["show_newsletter"] = True contact_dict["newsletter"] = is_subscribed(contact) else: contact_dict["show_newsletter"] = False
def _save_rename(self, instance, **kwargs): if hasattr(self, '_renaming') and self._renaming: return if self.auto_rename == NOTSET: try: self.auto_rename = config_value('THUMBNAIL', 'RENAME_IMAGES') except SettingNotSet: self.auto_rename = False image = getattr(instance, self.attname) if image and self.auto_rename: if self.name_field: field = getattr(instance, self.name_field) image = rename_by_field(image.path, '%s-%s-%s' \ % (instance.__class__.__name__, self.name, field ) ) else: # XXX this needs testing, maybe it can generate too long image names (max is 100) image = rename_by_field(image.path, '%s-%s-%s' \ % (instance.__class__.__name__, self.name, instance._get_pk_val() ) ) setattr(instance, self.attname, image) self._renaming = True instance.save() self._renaming = False
def testCronRebill(self): for order in OrderItem.objects.all(): price, expire_length = self.getTerms(order.product) if price is None: continue self.assertEqual( order.expire_date, datetime.date.today() + datetime.timedelta(days=expire_length)) #set expire date to today for upcoming cron test order.expire_date = datetime.date.today() order.save() order_count = OrderItem.objects.count() self.c = Client() self.response = self.c.get(prefix + '/checkout/cron/') self.assertEqual(self.response.status_code, 200) self.assertEqual(self.response.content, 'Authentication Key Required') from django.conf import settings self.response = self.c.get( prefix + '/checkout/cron/', data={'key': config_value('PAYMENT', 'CRON_KEY')}) self.assertEqual(self.response.status_code, 200) self.assertEqual(self.response.content, '') self.assert_(order_count < OrderItem.objects.count()) self.assertEqual(order_count, OrderItem.objects.count() / 2.0) for order in OrderItem.objects.filter( expire_date__gt=datetime.datetime.now()): price, expire_length = self.getTerms(order.product, ignore_trial=True) if price is None: continue self.assertEqual( order.expire_date, datetime.date.today() + datetime.timedelta(days=expire_length)) self.assertEqual(order.order.balance, Decimal('0.00'))
def displayDoc(request, id, doc): # Create the HttpResponse object with the appropriate PDF headers for an invoice or a packing slip order = get_object_or_404(Order, pk=id) shopDetails = Config.objects.get_current() filename_prefix = shopDetails.site.domain if doc == "invoice": filename = "%s-invoice.pdf" % filename_prefix template = "invoice.rml" elif doc == "packingslip": filename = "%s-packingslip.pdf" % filename_prefix template = "packing-slip.rml" elif doc == "shippinglabel": filename = "%s-shippinglabel.pdf" % filename_prefix template = "shipping-label.rml" else: return HttpResponseRedirect('/admin') response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=%s' % filename icon_uri = config_value('SHOP', 'LOGO_URI') t = loader.get_template(os.path.join('pdf', template)) c = Context({ 'filename' : filename, 'iconURI' : icon_uri, 'shopDetails' : shopDetails, 'order' : order, }) pdf = trml2pdf.parseString(smart_str(t.render(c))) response.write(pdf) return response
def activate(request, activation_key): """ Activates a user's account, if their key is valid and hasn't expired. """ from registration.models import RegistrationProfile activation_key = activation_key.lower() account = RegistrationProfile.objects.activate_user(activation_key) if account: # ** hack for logging in the user ** # when the login form is posted, user = authenticate(username=data['username'], password=data['password']) # ...but we cannot authenticate without password... so we work-around authentication account.backend = settings.AUTHENTICATION_BACKENDS[0] login(request, account) contact = Contact.objects.get(user=account) request.session['custID'] = contact.id send_welcome_email(contact.email, contact.first_name, contact.last_name) context = RequestContext( request, { 'account': account, 'expiration_days': config_value('SHOP', 'ACCOUNT_ACTIVATION_DAYS'), }) return render_to_response('registration/activate.html', context)
def order_tracking(request, order_id): order = None try: contact = Contact.objects.from_request(request, create=False) try: order = Order.objects.get(id__exact=order_id, contact=contact) except Order.DoesNotExist: pass except Contact.DoesNotExist: contact = None if order is None: return bad_or_missing( request, _("The order you have requested doesn't exist, or you don't have access to it." )) ctx = RequestContext( request, { 'default_view_tax': config_value('TAX', 'DEFAULT_VIEW_TAX'), 'contact': contact, 'order': order }) return render_to_response('shop/order_tracking.html', ctx)
def __init__(self, request, payment_module): self.request = request self.paymentModule = payment_module processor_module = payment_module.MODULE.load_module('processor') self.processor = processor_module.PaymentProcessor(self.paymentModule) self.viewTax = config_value('TAX', 'DEFAULT_VIEW_TAX') self.order = None self.cart = None self.extra_context = {} #to override the form_handler, set this #otherwise it will use the built-in `_onForm` self.onForm = self._onForm #to override the success method, set this #othewise it will use the built-in `_onSuccess` self.onSuccess = self._onSuccess #false on any "can not continue" error self.valid = False #the value to be returned from the view #an HttpResponse or a HttpRedirect self.response = None self.processorMessage = "" self.processorReasonCode = "" self.processorResults = None self.templates = { 'CONFIRM' : 'checkout/confirm.html', 'EMPTY_CART': 'checkout/empty_cart', '404': 'shop_404.html', }
def displayDoc(request, id, doc): # Create the HttpResponse object with the appropriate PDF headers for an invoice or a packing slip order = get_object_or_404(Order, pk=id) shopDetails = Config.objects.get_current() filename_prefix = shopDetails.site.domain if doc == "invoice": filename = "%s-invoice.pdf" % filename_prefix template = "invoice.rml" elif doc == "packingslip": filename = "%s-packingslip.pdf" % filename_prefix template = "packing-slip.rml" elif doc == "shippinglabel": filename = "%s-shippinglabel.pdf" % filename_prefix template = "shipping-label.rml" else: return HttpResponseRedirect('/admin') response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=%s' % filename icon_uri = config_value('SHOP', 'LOGO_URI') t = loader.get_template(os.path.join('pdf', template)) c = Context({ 'filename': filename, 'iconURI': icon_uri, 'shopDetails': shopDetails, 'order': order, }) pdf = trml2pdf.parseString(smart_str(t.render(c))) response.write(pdf) return response
def home(request, template="base_index.html"): # Display the category, its child categories, and its products. if request.method == "GET": currpage = request.GET.get('page', 1) else: currpage = 1 featured = display_featured() count = config_value('SHOP', 'NUM_PAGINATED') paginator = Paginator(featured, count) is_paged = False page = None try: paginator.validate_number(currpage) except EmptyPage: return bad_or_missing(request, _("Invalid page number")) is_paged = paginator.num_pages > 1 page = paginator.page(currpage) ctx = RequestContext( request, { 'all_products_list': page.object_list, 'is_paginated': is_paged, 'page_obj': page, 'paginator': paginator }) return render_to_response(template, ctx)
def home(request, template="base_index.html"): # Display the category, its child categories, and its products. if request.method == "GET": currpage = request.GET.get('page', 1) else: currpage = 1 featured = display_featured() count = config_value('SHOP','NUM_PAGINATED') paginator = Paginator(featured, count) is_paged = False page = None try: paginator.validate_number(currpage) except EmptyPage: return bad_or_missing(request, _("Invalid page number")) is_paged = paginator.num_pages > 1 page = paginator.page(currpage) ctx = RequestContext(request, { 'all_products_list' : page.object_list, 'is_paginated' : is_paged, 'page_obj' : page, 'paginator' : paginator }) return render_to_response(template, ctx)
def testBalanceMethods(self): order = TestOrderFactory() order.recalculate_total(save=False) price = order.total subtotal = order.sub_total self.assertEqual(subtotal, Decimal('25.00')) self.assertEqual(price, Decimal('35.00')) self.assertEqual(order.balance, price) paytype = config_value('PAYMENT', 'MODULES')[0] pmt = OrderPayment(order=order, payment=paytype, amount=Decimal("5.00")) pmt.save() self.assertEqual(order.balance, Decimal("30.00")) self.assertEqual(order.balance_paid, Decimal("5.00")) self.assertTrue(order.is_partially_paid) pmt = OrderPayment(order=order, payment=paytype, amount=Decimal("30.00")) pmt.save() self.assertEqual(order.balance, Decimal("0.00")) self.assertFalse(order.is_partially_paid) self.assertTrue(order.paid_in_full)
def testCronRebill(self): for order in OrderItem.objects.all(): price, expire_length = self.getTerms(order.product) if price is None: continue self.assertEqual(order.expire_date, datetime.date.today() + datetime.timedelta(days=expire_length)) #set expire date to today for upcoming cron test order.expire_date = datetime.date.today() order.save() order_count = OrderItem.objects.count() self.c = Client() self.response = self.c.get(prefix+'/checkout/cron/') self.assertEqual(self.response.status_code, 200) self.assertEqual(self.response.content, 'Authentication Key Required') from django.conf import settings self.response = self.c.get(prefix+'/checkout/cron/', data={'key': config_value('PAYMENT','CRON_KEY')}) self.assertEqual(self.response.status_code, 200) self.assertEqual(self.response.content, '') self.assert_(order_count < OrderItem.objects.count()) self.assertEqual(order_count, OrderItem.objects.count()/2.0) for order in OrderItem.objects.filter(expire_date__gt=datetime.datetime.now()): price, expire_length = self.getTerms(order.product, ignore_trial=True) if price is None: continue self.assertEqual(order.expire_date, datetime.date.today() + datetime.timedelta(days=expire_length)) self.assertEqual(order.order.balance, Decimal('0.00'))
def cartitem_total(parser, token): """Returns the line total for the cartitem, possibly with tax added. If currency evaluates true, then return the total formatted through money_format. Example:: {% cartitem_total cartitem [show_tax] [currency] %} """ tokens = token.contents.split() if len(tokens) < 2: raise template.TemplateSyntaxError, "'%s' tag requires a cartitem argument" % tokens[0] cartitem = tokens[1] if len(tokens) > 2: show_tax = tokens[2] else: show_tax = config_value('TAX', 'DEFAULT_VIEW_TAX') if len(tokens) >3: show_currency = tokens[3] else: show_currency = 'True' return CartitemTotalNode(cartitem, show_currency, show_tax)
def cartitem_total(parser, token): """Returns the line total for the cartitem, possibly with tax added. If currency evaluates true, then return the total formatted through money_format. Example:: {% cartitem_total cartitem [show_tax] [currency] %} """ tokens = token.contents.split() if len(tokens) < 2: raise template.TemplateSyntaxError, "'%s' tag requires a cartitem argument" % tokens[ 0] cartitem = tokens[1] if len(tokens) > 2: show_tax = tokens[2] else: show_tax = config_value('TAX', 'DEFAULT_VIEW_TAX') if len(tokens) > 3: show_currency = tokens[3] else: show_currency = 'True' return CartitemTotalNode(cartitem, show_currency, show_tax)
def google_adwords_signup(context): """ Output signup info in the format that Google adwords needs. """ request = context['request'] try: request = context['request'] except KeyError: print >> sys.stderr, "Template satchmo.show.templatetags.google.google_adwords_sale couldn't get the request from the context. Are you missing the request context_processor?" return "" secure = request.is_secure() try: language_code = request.LANGUAGE_CODE except AttributeError: language_code = settings.LANGUAGE_CODE return ({ "GOOGLE_ADWORDS_ID": config_value('GOOGLE', 'ADWORDS_ID'), 'Store': settings.SITE_NAME, 'value': 1, 'label': 'signup', 'secure': secure, 'language_code': language_code })
def __init__(self, request, payment_module): self.request = request self.paymentModule = payment_module processor_module = payment_module.MODULE.load_module('processor') self.processor = processor_module.PaymentProcessor(self.paymentModule) self.viewTax = config_value('TAX', 'DEFAULT_VIEW_TAX') self.order = None self.cart = None self.extra_context = {} #to override the form_handler, set this #otherwise it will use the built-in `_onForm` self.onForm = self._onForm #to override the success method, set this #othewise it will use the built-in `_onSuccess` self.onSuccess = self._onSuccess #false on any "can not continue" error self.valid = False #the value to be returned from the view #an HttpResponse or a HttpRedirect self.response = None self.processorMessage = "" self.processorReasonCode = "" self.processorResults = None self.templates = { 'CONFIRM': 'checkout/confirm.html', 'EMPTY_CART': 'checkout/empty_cart', '404': 'shop_404.html', }
def __init__(self, request, paymentmodule, *args, **kwargs): super(SimplePayShipForm, self).__init__(*args, **kwargs) self.order = None self.orderpayment = None try: self.tempCart = Cart.objects.from_request(request) if self.tempCart.numItems > 0: products = [item.product for item in self.tempCart.cartitem_set.all()] sale = find_best_auto_discount(products) if sale: self.fields['discount'].initial = sale.code except Cart.DoesNotExist: self.tempCart = None try: self.tempContact = Contact.objects.from_request(request) except Contact.DoesNotExist: self.tempContact = None if 'default_view_tax' in kwargs: default_view_tax = kwargs['default_view_tax'] else: default_view_tax = config_value('TAX', 'TAX_SHIPPING') shipping_choices, shipping_dict = _get_shipping_choices(request, paymentmodule, self.tempCart, self.tempContact, default_view_tax=default_view_tax) self.fields['shipping'].choices = shipping_choices self.shipping_dict = shipping_dict signals.payment_form_init.send(SimplePayShipForm, form=self)
def test_product(self): # Test for an easily missed reversion. When you lookup a productvariation product then # you should get the page of the parent configurableproduct, but with the options for # that variation already selected response = self.client.get(prefix+'/product/neat-book_soft/') self.assertContains(response, 'option value="soft" selected="selected"') self.assertContains(response, smart_str("%s5.00" % config_value('SHOP', 'CURRENCY')))
def testBalanceMethods(self): order = make_test_order(self.US, "", include_non_taxed=True) order.recalculate_total(save=False) price = order.total subtotal = order.sub_total self.assertEqual(subtotal, Decimal("105.00")) self.assertEqual(price, Decimal("115.00")) self.assertEqual(order.balance, price) paytype = config_value("PAYMENT", "MODULES")[0] pmt = OrderPayment(order=order, payment=paytype, amount=Decimal("5.00")) pmt.save() self.assertEqual(order.balance, Decimal("110.00")) self.assertEqual(order.balance_paid, Decimal("5.00")) self.assert_(order.is_partially_paid) pmt = OrderPayment(order=order, payment=paytype, amount=Decimal("110.00")) pmt.save() self.assertEqual(order.balance, Decimal("0.00")) self.assertEqual(order.is_partially_paid, False) self.assert_(order.paid_in_full)
def activate(request, activation_key): """ Activates a user's account, if their key is valid and hasn't expired. """ from registration.models import RegistrationProfile activation_key = activation_key.lower() account = RegistrationProfile.objects.activate_user(activation_key) if account: # ** hack for logging in the user ** # when the login form is posted, user = authenticate(username=data['username'], password=data['password']) # ...but we cannot authenticate without password... so we work-around authentication account.backend = settings.AUTHENTICATION_BACKENDS[0] login(request, account) contact = Contact.objects.get(user=account) request.session['custID'] = contact.id send_welcome_email(contact.email, contact.first_name, contact.last_name) context = RequestContext(request, { 'account': account, 'expiration_days': config_value('SHOP', 'ACCOUNT_ACTIVATION_DAYS'), }) return render_to_response('registration/activate.html', context)
def _get_shipping_choices(paymentmodule, cart, contact): """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 = {} for module in config_value('SHIPPING', 'MODULES'): #Create the list of information the user will see shipping_module = load_module(module) shipping_instance = shipping_module.Calc(cart, contact) if shipping_instance.valid(): template = lookup_template(paymentmodule, 'shipping_options.html') t = loader.get_template(template) shipcost = shipping_instance.cost() c = Context({ 'amount': shipcost, 'description': shipping_instance.description(), 'method': shipping_instance.method(), 'expected_delivery': shipping_instance.expectedDelivery() }) shipping_options.append((shipping_instance.id, t.render(c))) shipping_dict[shipping_instance.id] = shipcost return shipping_options, shipping_dict
def get_product(request, category_slug, brand_slug, product_slug, selected_options=(), include_tax=NOTSET, default_view_tax=NOTSET): """Basic product view""" try: product = Product.objects.get_by_site(active=True, slug=product_slug) except Product.DoesNotExist: return bad_or_missing(request, _('The product you have requested does not exist.')) try: category = Category.objects.get(slug=category_slug) except Category.DoesNotExist: category = None brand = Brand.objects.get(slug=brand_slug) if default_view_tax == NOTSET: default_view_tax = config_value('TAX', 'DEFAULT_VIEW_TAX') if default_view_tax: include_tax = True elif include_tax == NOTSET: include_tax = default_view_tax if default_view_tax: include_tax = True subtype_names = product.get_subtypes() if 'ProductVariation' in subtype_names: selected_options = product.productvariation.unique_option_ids # Display the ConfigurableProduct that this ProductVariation belongs to. product = product.productvariation.parent.product subtype_names = product.get_subtypes() best_discount = find_best_auto_discount(product) extra_context = { 'product': product, 'category': category, 'brand': brand, 'default_view_tax': default_view_tax, 'sale': best_discount, } # Get the template context from the Product. extra_context = product.add_template_context( context=extra_context, request=request, selected_options=selected_options, include_tax=include_tax, default_view_tax=default_view_tax ) if include_tax: tax_amt = get_tax(request.user, product, 1) extra_context['product_tax'] = tax_amt extra_context['price_with_tax'] = product.unit_price + tax_amt template = find_product_template(product, producttypes=subtype_names) context = RequestContext(request, extra_context) return http.HttpResponse(template.render(context))
def cost(self): """ Complex calculations can be done here as long as the return value is a dollar figure """ for cartitem in self.cart.cartitem_set.all(): if cartitem.product.is_shippable: return config_value('SHIPPING', 'FLAT_RATE') return Decimal("0.00")
def shipping_methods(): methods = [] modules = config_value('SHIPPING', 'MODULES') logger.debug('Getting shipping methods: %s', modules) for m in modules: module = load_module(m) methods.extend(module.get_methods()) return methods
def show_tracker(secure=False): """ Output the google tracker code. """ return ({ "GOOGLE_CODE": config_value('GOOGLE', 'ANALYTICS_CODE'), "secure": secure })
def cost(self): """ Complex calculations can be done here as long as the return value is a dollar figure """ for cartitem in self.cart.cartitem_set.all(): if cartitem.product.is_shippable: return config_value("SHIPPING", "FLAT_RATE") return Decimal("0.00")
def valid(self, order=None): """ Exclude countries that we don't want to ship to, also exclude the United Kingdom as this shipping module doesn't support GB. """ excluded_countries = config_value('satchmo.shipping.modules.royalmailcontract', 'EXCLUDE_COUNTRY') excluded_countries.append(u'GB') return self.contact.shipping_address.country.iso2_code not in excluded_countries
def send_order_notice(new_order, template='email/order_placed_notice.txt'): """Send an order confirmation mail to the owner. """ from satchmo.shop.models import Config if config_value("PAYMENT", "ORDER_EMAIL_OWNER"): shop_config = Config.objects.get_current() shop_email = shop_config.store_email t = loader.get_template(template) c = Context({'order': new_order, 'shop_config': shop_config}) subject = _("New order on %(shop_name)s") % { 'shop_name': shop_config.store_name } eddresses = [ shop_email, ] more = config_value("PAYMENT", "ORDER_EMAIL_EXTRA") if more: more = [m.strip() for m in more.split(',')] for m in more: if not m in eddresses: eddresses.append(m) eddresses = [e for e in eddresses if e] if not eddresses: log.warn("No shop owner email specified, skipping owner_email") return try: body = t.render(c) message = EmailMessage(subject, body, shop_email, eddresses) message.send() except (SocketError, SMTPRecipientsRefused), e: if settings.DEBUG: log.error('Error sending mail: %s' % e) log.warn( 'Ignoring email error, since you are running in DEBUG mode. Email was:\nTo:%s\nSubject: %s\n---\n%s', ",".join(eddresses), subject, body) else: log.fatal('Error sending mail: %s' % e) raise IOError( 'Could not send email, please check to make sure your email settings are correct, and that you are not being blocked by your ISP.' )
def display_featured(limit=None, random=None): """ Used by the index generic view to choose how the featured products are displayed. Items can be displayed randomly or all in order """ if random: random_display = random else: random_display = config_value('SHOP', 'RANDOM_FEATURED') if limit: num_to_display = limit else: num_to_display = config_value('SHOP', 'NUM_DISPLAY') q = Product.objects.featured_by_site().filter(items_in_stock__gt=0) if not random_display: return q[:num_to_display] else: return q.order_by('?')[:num_to_display]
def contact_info(request): """View which collects demographic information from customer.""" #First verify that the cart exists and has items if request.session.get('cart'): tempCart = Cart.objects.get(id=request.session['cart']) if tempCart.numItems == 0: return render_to_response('checkout/empty_cart.html', RequestContext(request)) else: return render_to_response('checkout/empty_cart.html', RequestContext(request)) init_data = {} areas, countries, only_country = get_area_country_options(request) contact = Contact.from_request(request, create=False) if request.POST: new_data = request.POST.copy() if not tempCart.is_shippable: new_data['copy_address'] = True form = PaymentContactInfoForm(countries, areas, new_data, initial=init_data) if form.is_valid(): if contact is None and request.user: contact = Contact(user=request.user) custID = form.save(contact=contact, update_newsletter=False) request.session['custID'] = custID #TODO - Create an order here and associate it with a session modulename = 'PAYMENT_' + new_data['paymentmethod'] paymentmodule = config_get_group(modulename) url = lookup_url(paymentmodule, 'satchmo_checkout-step2') return http.HttpResponseRedirect(url) else: if contact: #If a person has their contact info, make sure we populate it in the form for item in contact.__dict__.keys(): init_data[item] = getattr(contact,item) if contact.shipping_address: for item in contact.shipping_address.__dict__.keys(): init_data["ship_"+item] = getattr(contact.shipping_address,item) if contact.billing_address: for item in contact.billing_address.__dict__.keys(): init_data[item] = getattr(contact.billing_address,item) if contact.primary_phone: init_data['phone'] = contact.primary_phone.phone else: # Allow them to login from this page. request.session.set_test_cookie() form = PaymentContactInfoForm(countries, areas, initial=init_data) context = RequestContext(request, { 'form': form, 'country': only_country, 'paymentmethod_ct': len(config_value('PAYMENT', 'MODULES')) }) return render_to_response('checkout/form.html', context)
def upload_dir(instance, filename): raw = "images/" try: raw = config_value('PRODUCT', 'IMAGE_DIR') except SettingNotSet: pass except ImportError, e: log.warn("Error getting upload_dir, OK if you are in SyncDB.")
def display_bestsellers(request, count=0, template='product/best_sellers.html'): """Display a list of the products which have sold the most""" if count == 0: count = config_value('SHOP', 'NUM_PAGINATED') ctx = RequestContext(request, { 'products' : bestsellers(count), }) return render_to_response(template, ctx)
def display_bestratings(request, count=0, template='product/best_ratings.html'): """Display a list of the products with the best ratings in comments""" if count is None: count = config_value('SHOP', 'NUM_DISPLAY') ctx = RequestContext(request, { 'products' : highest_rated(), }) return render_to_response(template, ctx)
def valid(self, order=None): """ Exclude countries that we don't want to ship to, also exclude the United Kingdom as this shipping module doesn't support GB. """ excluded_countries = config_value( 'satchmo.shipping.modules.royalmailcontract', 'EXCLUDE_COUNTRY') excluded_countries.append(u'GB') return self.contact.shipping_address.country.iso2_code not in excluded_countries
def test_product(self): # Test for an easily missed reversion. When you lookup a productvariation product then # you should get the page of the parent configurableproduct, but with the options for # that variation already selected response = self.client.get(prefix + '/product/neat-book-soft/') self.assertContains(response, 'option value="soft" selected="selected"') self.assertContains( response, smart_str("%s5.00" % config_value('SHOP', 'CURRENCY')))
def cost(self): """ Complex calculations can be done here as long as the return value is a dollar figure """ fee = Decimal("0.00") rate = config_value('SHIPPING', 'PER_RATE') for cartitem in self.cart.cartitem_set.all(): if cartitem.product.is_shippable: fee += rate * cartitem.quantity return fee
def get_subtypes(self): types = [] for key in config_value('PRODUCT', 'PRODUCT_TYPES'): app, subtype = key.split("::") try: if getattr(self, subtype.lower()): types += [subtype] except models.ObjectDoesNotExist: pass return tuple(types)