def test_multi_site(self): basket = factories.create_basket(empty=True) site1 = factories.SiteFactory() site2 = factories.SiteFactory() request = HttpRequest() request.META['SERVER_PORT'] = 80 request.META['SERVER_NAME'] = site1.domain user = factories.UserFactory() add_product(basket, D('12.00')) shipping_method = Free() shipping_charge = shipping_method.calculate(basket) order_total = OrderTotalCalculator().calculate(basket, shipping_charge) billing_address = factories.BillingAddressFactory() shipping_address = factories.ShippingAddressFactory() order_submission_data = {'user': user, 'order_number': '12345', 'basket': basket, 'shipping_method': shipping_method, 'shipping_charge': shipping_charge, 'order_total': order_total, 'billing_address': billing_address, 'shipping_address': shipping_address, 'request': request} OrderPlacementMixin().place_order(**order_submission_data) order1 = Order.objects.get(number='12345') self.assertEqual(order1.site, site1) add_product(basket, D('12.00')) request.META['SERVER_NAME'] = site2.domain order_submission_data['order_number'] = '12346' order_submission_data['request'] = request OrderPlacementMixin().place_order(**order_submission_data) order2 = Order.objects.get(number='12346') self.assertEqual(order2.site, site2)
def test_multiple_payment_events(self): basket = factories.create_basket(empty=True) user = factories.UserFactory() add_product(basket, D('100.00')) order_placement = OrderPlacementMixin() order_placement.add_payment_event('Gift Card Payment', D('10')) order_placement.add_payment_event('Credit Card Payment', D('90')) shipping_method = Free() shipping_charge = shipping_method.calculate(basket) order_total = OrderTotalCalculator().calculate(basket, shipping_charge) billing_address = factories.BillingAddressFactory() shipping_address = factories.ShippingAddressFactory() order_submission_data = {'user': user, 'order_number': '12345', 'basket': basket, 'shipping_method': shipping_method, 'shipping_charge': shipping_charge, 'order_total': order_total, 'billing_address': billing_address, 'shipping_address': shipping_address} order_placement.place_order(**order_submission_data) order1 = Order.objects.get(number='12345') self.assertEqual(order1.payment_events.count(), 2) event1 = order1.payment_events.all()[0] event2 = order1.payment_events.all()[1] self.assertEqual(event1.event_type.name, 'Credit Card Payment') self.assertEqual(event1.amount, D('90')) self.assertEqual(event1.lines.count(), 1) self.assertEqual(event2.event_type.name, 'Gift Card Payment') self.assertEqual(event2.amount, D('10')) self.assertEqual(event2.lines.count(), 1)
def test_multiple_payment_events(self): basket = factories.create_basket(empty=True) user = factories.UserFactory() add_product(basket, D('100.00')) order_placement = OrderPlacementMixin() order_placement.add_payment_event('Gift Card Payment', D('10')) order_placement.add_payment_event('Credit Card Payment', D('90')) shipping_method = Free() shipping_charge = shipping_method.calculate(basket) order_total = OrderTotalCalculator().calculate(basket, shipping_charge) billing_address = factories.BillingAddressFactory() shipping_address = factories.ShippingAddressFactory() order_submission_data = { 'user': user, 'order_number': '12345', 'basket': basket, 'shipping_method': shipping_method, 'shipping_charge': shipping_charge, 'order_total': order_total, 'billing_address': billing_address, 'shipping_address': shipping_address } order_placement.place_order(**order_submission_data) order1 = Order.objects.get(number='12345') self.assertEqual(order1.payment_events.count(), 2) event1 = order1.payment_events.all()[0] event2 = order1.payment_events.all()[1] self.assertEqual(event1.event_type.name, 'Credit Card Payment') self.assertEqual(event1.amount, D('90')) self.assertEqual(event1.lines.count(), 1) self.assertEqual(event2.event_type.name, 'Gift Card Payment') self.assertEqual(event2.amount, D('10')) self.assertEqual(event2.lines.count(), 1)
def place_order(self, basket, total_incl_tax=None, total_excl_tax=None, user=None, shipping_method=None, shipping_address=None, billing_address=None, order_number=None, status=None, **kwargs): """ Placing an order involves creating all the relevant models based on the basket and session data. """ # Only a basket instance is required to place an order - everything else can be set # to defaults if basket.is_empty: raise ValueError(_("Empty baskets cannot be submitted")) if not shipping_method: shipping_method = Free() if total_incl_tax is None or total_excl_tax is None: total_incl_tax = basket.total_incl_tax + shipping_method.basket_charge_incl_tax( ) total_excl_tax = basket.total_excl_tax + shipping_method.basket_charge_excl_tax( ) if not order_number: generator = OrderNumberGenerator() order_number = generator.order_number(basket) if not status and hasattr(settings, 'OSCAR_INITIAL_ORDER_STATUS'): status = getattr(settings, 'OSCAR_INITIAL_ORDER_STATUS') try: Order._default_manager.get(number=order_number) except Order.DoesNotExist: pass else: raise ValueError( _("There is already an order with number %s") % order_number) # Ok - everything seems to be in order, let's place the order order = self.create_order_model(user, basket, shipping_address, shipping_method, billing_address, total_incl_tax, total_excl_tax, order_number, status, **kwargs) for line in basket.all_lines(): self.create_line_models(order, line) self.update_stock_records(line) for discount in basket.get_discounts(): self.create_discount_model(order, discount) self.record_discount(discount) for voucher in basket.vouchers.all(): self.record_voucher_usage(order, voucher, user) # Send signal for analytics to pick up order_placed.send(sender=self, order=order, user=user) return order
def place_order(self, basket, total_incl_tax=None, total_excl_tax=None, user=None, shipping_method=None, shipping_address=None, billing_address=None, order_number=None, status=None, **kwargs): """ Placing an order involves creating all the relevant models based on the basket and session data. """ # Only a basket instance is required to place an order - everything else can be set # to defaults if basket.is_empty: raise ValueError(_("Empty baskets cannot be submitted")) if not shipping_method: shipping_method = Free() if total_incl_tax is None or total_excl_tax is None: total_incl_tax = basket.total_incl_tax + shipping_method.basket_charge_incl_tax() total_excl_tax = basket.total_excl_tax + shipping_method.basket_charge_excl_tax() if not order_number: generator = OrderNumberGenerator() order_number = generator.order_number(basket) if not status and hasattr(settings, 'OSCAR_INITIAL_ORDER_STATUS'): status = getattr(settings, 'OSCAR_INITIAL_ORDER_STATUS') try: Order._default_manager.get(number=order_number) except Order.DoesNotExist: pass else: raise ValueError(_("There is already an order with number %s") % order_number) # Ok - everything seems to be in order, let's place the order order = self.create_order_model( user, basket, shipping_address, shipping_method, billing_address, total_incl_tax, total_excl_tax, order_number, status, **kwargs) for line in basket.all_lines(): self.create_line_models(order, line) self.update_stock_records(line) for application in basket.offer_applications: # Trigger any deferred benefits from offers and capture the # resulting message application['message'] = application['offer'].apply_deferred_benefit(basket) # Record offer application results if application['result'].affects_shipping: # Skip zero shipping discounts if shipping_method.discount <= D('0.00'): continue # If a shipping offer, we need to grab the actual discount off # the shipping method instance, which should be wrapped in an # OfferDiscount instance. application['discount'] = shipping_method.discount self.create_discount_model(order, application) self.record_discount(application) for voucher in basket.vouchers.all(): self.record_voucher_usage(order, voucher, user) # Send signal for analytics to pick up order_placed.send(sender=self, order=order, user=user) return order
def place_order(self, basket, total_incl_tax=None, total_excl_tax=None, user=None, shipping_method=None, shipping_address=None, billing_address=None, order_number=None, status=None, **kwargs): """ Placing an order involves creating all the relevant models based on the basket and session data. """ # Only a basket instance is required to place an order - everything else can be set # to defaults if basket.is_empty: raise ValueError(_("Empty baskets cannot be submitted")) if not shipping_method: shipping_method = Free() if total_incl_tax is None or total_excl_tax is None: total_incl_tax = basket.total_incl_tax + shipping_method.basket_charge_incl_tax() total_excl_tax = basket.total_excl_tax + shipping_method.basket_charge_excl_tax() if not order_number: generator = OrderNumberGenerator() order_number = generator.order_number(basket) if not status and hasattr(settings, 'OSCAR_INITIAL_ORDER_STATUS'): status = getattr(settings, 'OSCAR_INITIAL_ORDER_STATUS') try: Order._default_manager.get(number=order_number) except Order.DoesNotExist: pass else: raise ValueError(_("There is already an order with number %s") % order_number) # Ok - everything seems to be in order, let's place the order order = self.create_order_model(user, basket, shipping_address, shipping_method, billing_address, total_incl_tax, total_excl_tax, order_number, status, **kwargs) for line in basket.all_lines(): self.create_line_models(order, line) self.update_stock_records(line) # Record discounts (including any on the shipping method) for discount in basket.get_discounts(): self.create_discount_model(order, discount) self.record_discount(discount) if shipping_method.is_discounted: discount = shipping_method.get_discount() self.create_discount_model(order, discount, is_shipping_discount=True) self.record_discount(discount) for voucher in basket.vouchers.all(): self.record_voucher_usage(order, voucher, user) # Send signal for analytics to pick up order_placed.send(sender=self, order=order, user=user) return order
class Repository(CoreRepository): """ This class is included so that there is a choice of shipping methods. Oscar's default behaviour is to only have one which means you can't test the shipping features of PayFast. """ methods = [Free(), FixedPrice(D('10.00'), D('10.00'))]
def create_order(number=None, basket=None, user=None, shipping_address=None, shipping_method=None, billing_address=None, total_incl_tax=None, total_excl_tax=None, **kwargs): """ Helper method for creating an order for testing """ if not basket: basket = Basket.objects.create() basket.add_product(create_product(price=D('10.00'))) if not basket.id: basket.save() if shipping_method is None: shipping_method = Free() if total_incl_tax is None or total_excl_tax is None: calc = OrderTotalCalculator() total_incl_tax = calc.order_total_incl_tax(basket, shipping_method) total_excl_tax = calc.order_total_excl_tax(basket, shipping_method) order = OrderCreator().place_order( order_number=number, user=user, basket=basket, shipping_address=shipping_address, shipping_method=shipping_method, billing_address=billing_address, total_incl_tax=total_incl_tax, total_excl_tax=total_excl_tax, **kwargs ) return order
def setUp(self): self.non_discount_methods = [ Free(), FixedPrice(D('10.00'), D('10.00')), OrderAndItemCharges(price_per_order=D('5.00'), price_per_item=D('1.00')) ]
def get_shipping_method(self, basket=None): method = self.checkout_session.shipping_method(basket) # We default to using free shipping if not method: method = Free() return method
def test_saves_shipping_code(self): add_product(self.basket, D('12.00')) free_method = Free() order = place_order(self.creator, basket=self.basket, order_number='1234', shipping_method=free_method) self.assertEqual(order.shipping_code, free_method.code)
def place_order(self, basket, total, # noqa (too complex (12)) user=None, shipping_method=None, shipping_address=None, billing_address=None, order_number=None, status=None, **kwargs): """ Placing an order involves creating all the relevant models based on the basket and session data. """ if basket.is_empty: raise ValueError(_("Empty baskets cannot be submitted")) if not shipping_method: shipping_method = Free() if not order_number: generator = OrderNumberGenerator() order_number = generator.order_number(basket) if not status and hasattr(settings, 'OSCAR_INITIAL_ORDER_STATUS'): status = getattr(settings, 'OSCAR_INITIAL_ORDER_STATUS') try: Order._default_manager.get(number=order_number) except Order.DoesNotExist: pass else: raise ValueError(_("There is already an order with number %s") % order_number) # Ok - everything seems to be in order, let's place the order order = self.create_order_model( user, basket, shipping_address, shipping_method, billing_address, total, order_number, status, **kwargs) for line in basket.all_lines(): self.create_line_models(order, line) self.update_stock_records(line) for application in basket.offer_applications: # Trigger any deferred benefits from offers and capture the # resulting message application['message'] \ = application['offer'].apply_deferred_benefit(basket) # Record offer application results if application['result'].affects_shipping: # Skip zero shipping discounts if shipping_method.discount <= D('0.00'): continue # If a shipping offer, we need to grab the actual discount off # the shipping method instance, which should be wrapped in an # OfferDiscount instance. application['discount'] = shipping_method.discount self.create_discount_model(order, application) self.record_discount(application) for voucher in basket.vouchers.all(): self.record_voucher_usage(order, voucher, user) # Send signal for analytics to pick up order_placed.send(sender=self, order=order, user=user) return order
def place_order(creator, **kwargs): """ Helper function to place an order without the boilerplate """ if 'shipping_method' not in kwargs: kwargs['shipping_method'] = Free() if 'total' not in kwargs: kwargs['total'] = calculators.OrderTotalCalculator().calculate( basket=kwargs['basket'], shipping_method=kwargs['shipping_method']) return creator.place_order(**kwargs)
def get_shipping_method(self, basket, shipping_address=None, **kwargs): """ Return the shipping method used """ if not basket.is_shipping_required(): return NoShippingRequired() method = Free() return method
def get_available_shipping_methods(self, basket, shipping_addr=None, **kwargs): """ Return a list of all applicable shipping method instances for a given basket, address etc. """ methods = [Free(), FixedPrice(D('10.00'), D('10.00'))] return methods
def get_shipping_method(self, basket=None): method = self.checkout_session.shipping_method() if method: if not basket: basket = self.request.basket method.set_basket(basket) else: # We default to using free shipping method = Free() return method
class TestPlacingOrderForDigitalGoods(TestCase): def setUp(self): self.creator = OrderCreator() self.basket = factories.create_basket(empty=True) self.shipping_method = Free() self.shipping_method.set_basket(self.basket) def test_does_not_allocate_stock(self): ProductClass.objects.create(name="Digital", track_stock=False) product = factories.create_product(product_class="Digital") record = factories.create_stockrecord(product, num_in_stock=None) self.assertTrue(record.num_allocated is None) add_product(self.basket, D('12.00'), product=product) place_order(self.creator, basket=self.basket, order_number='1234') product = Product.objects.get(id=product.id) stockrecord = product.stockrecords.all()[0] self.assertTrue(stockrecord.num_in_stock is None) self.assertTrue(stockrecord.num_allocated is None)
def perform_action(self): basket = Mock() basket.id = 1 basket.total_incl_tax = D('200') basket.all_lines = Mock(return_value=[]) basket.offer_discounts = [] basket.voucher_discounts = [] basket.shipping_discounts = [] methods = [Free()] url_str = get_paypal_url(basket, methods) self.url = URL.from_string(url_str)
def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): """ Return a list of all applicable shipping method objects for a given basket. We default to returning the Method models that have been defined but this behaviour can easily be overridden by subclassing this class and overriding this method. """ methods = [Free()] return self.prime_methods(basket, methods)
class TestPlacingOrderForDigitalGoods(TestCase): def setUp(self): self.creator = OrderCreator() self.basket = factories.create_basket(empty=True) self.shipping_method = Free() self.shipping_method.set_basket(self.basket) def test_does_not_allocate_stock(self): ProductClass.objects.create( name="Digital", track_stock=False) product = factories.create_product(product_class="Digital") record = factories.create_stockrecord(product, num_in_stock=None) self.assertTrue(record.num_allocated is None) add_product(self.basket, D('12.00'), product=product) place_order(self.creator, basket=self.basket, order_number='1234') product = Product.objects.get(id=product.id) stockrecord = product.stockrecords.all()[0] self.assertTrue(stockrecord.num_in_stock is None) self.assertTrue(stockrecord.num_allocated is None)
class FreeTest(TestCase): def setUp(self): self.method = Free() def test_shipping_is_free_for_empty_basket(self): basket = Basket() self.method.set_basket(basket) self.assertEquals(D('0.00'), self.method.basket_charge_incl_tax()) self.assertEquals(D('0.00'), self.method.basket_charge_excl_tax()) def test_shipping_is_free_for_nonempty_basket(self): basket = Basket() basket.add_product(create_product()) self.method.set_basket(basket) self.assertEquals(D('0.00'), self.method.basket_charge_incl_tax()) self.assertEquals(D('0.00'), self.method.basket_charge_excl_tax())
class FreeTest(TestCase): def setUp(self): self.method = Free() def test_shipping_is_free_for_empty_basket(self): basket = Basket() self.method.set_basket(basket) self.assertEquals(D("0.00"), self.method.basket_charge_incl_tax()) self.assertEquals(D("0.00"), self.method.basket_charge_excl_tax()) def test_shipping_is_free_for_nonempty_basket(self): basket = Basket() basket.add_product(create_product()) self.method.set_basket(basket) self.assertEquals(D("0.00"), self.method.basket_charge_incl_tax()) self.assertEquals(D("0.00"), self.method.basket_charge_excl_tax())
class Repository(CoreRepository): """ This class is included so that there is a choice of shipping methods. Oscar's default behaviour is to only have one which means you can't test the shipping features of PayPal. """ methods = [Free(), FixedPrice(D('10.00'))] def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): return self.prime_methods(basket, self.methods) def find_by_code(self, code, basket): for method in self.methods: if code == method.code: return self.prime_method(basket, method)
def test_zero_shipping_discount_is_not_created(self): add_product(self.basket, D('12.00')) offer = self.apply_20percent_shipping_offer() shipping = Free() shipping = Repository().apply_shipping_offer(self.basket, shipping, offer) place_order(self.creator, basket=self.basket, order_number='1234', shipping_method=shipping) order = Order.objects.get(number='1234') # No shipping discount self.assertEqual(0, len(order.shipping_discounts)) self.assertEqual(D('0.00'), order.shipping_incl_tax) self.assertEqual(D('12.00'), order.total_incl_tax)
from oscar.apps.shipping.methods import Free, NoShippingRequired from oscar.apps.shipping.repository import Repository as CoreRepository # Dummy shipping methods free1 = Free() free1.code = 'free1' free1.description = 'Ship by van' free2 = Free() free2.code = 'free2' free2.description = 'Ship by boat' class Repository(CoreRepository): methods = {free1.code: free1, free2.code: free2} def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): methods = self.methods.values() return self.add_basket_to_methods(basket, methods) def find_by_code(self, code): if code == NoShippingRequired.code: return NoShippingRequired() return self.methods.get(code, None)
def setUp(self): self.creator = OrderCreator() self.basket = factories.create_basket(empty=True) self.shipping_method = Free() self.shipping_method.set_basket(self.basket)
def setUp(self): self.method = Free()
class Repository(CoreRepository): methods = [Free(), FixedPrice(D('10.00'), D('10.00'))]
class StubRepository(Repository): """ Custom shipping methods """ methods = (FixedPrice(D('5.00'), D('5.00')), Free())
def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): methods = [Free(), FixedPrice(D('10.00')), FixedPrice(D('20.00'))] return self.prime_methods(basket, methods)
from oscar.apps.shipping.methods import Free from oscar.apps.shipping.repository import Repository as CoreRepository # Dummy shipping methods free1 = Free() free1.code = 'free1' free1.description = 'Ship by van' free2 = Free() free2.code = 'free2' free2.description = 'Ship by boat' class Repository(CoreRepository): methods = { free1.code: free1, free2.code: free2 } def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): methods = self.methods.values() return self.add_basket_to_methods(basket, methods) def find_by_code(self, code): return self.methods.get(code, None)
def get_methods(self): return [Free(), FixedPrice(D('10.00'), D('10.00'))]
def setUp(self): self.basket = create_mock_basket() self.methods = [Free()]
class Repository(object): """ Repository class responsible for returning ShippingMethod objects for a given user, basket etc """ methods = (Free(), ) def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs): """ Return a list of all applicable shipping method objects for a given basket. We default to returning the Method models that have been defined but this behaviour can easily be overridden by subclassing this class and overriding this method. """ return self.prime_methods(basket, self.methods) def get_default_shipping_method(self, user, basket, shipping_addr=None, **kwargs): """ Return a 'default' shipping method to show on the basket page to give the customer an indication of what their order will cost. """ methods = self.get_shipping_methods(user, basket, shipping_addr, **kwargs) if len(methods) == 0: raise ImproperlyConfigured( _("You need to define some shipping methods")) # Choose the cheapest method by default return min(methods, key=lambda method: method.basket_charge_incl_tax()) def prime_methods(self, basket, methods): """ Prime a list of shipping method instances This involves injecting the basket instance into each and adding any discount wrappers. """ return [self.prime_method(basket, method) for method in methods] def prime_method(self, basket, method): """ Prime an individual method instance """ method.set_basket(basket) # If the basket has a shipping offer, wrap the shipping method with a # decorating class that applies the offer discount to the shipping # charge. if basket.offer_applications.shipping_discounts: # We assume there is only one shipping discount available discount = basket.offer_applications.shipping_discounts[0] if method.basket_charge_incl_tax > D('0.00'): return OfferDiscount(method, discount['offer']) return method def find_by_code(self, code, basket): """ Return the appropriate Method object for the given code """ for method in self.methods: if method.code == code: return self.prime_method(basket, method) # Check for NoShippingRequired as that is a special case if code == NoShippingRequired.code: return self.prime_method(basket, NoShippingRequired())