Example #1
0
    def configure(self, request, instance=None, edit=True):
        super(OrderForm, self).configure(request, instance, edit)

        if 'cubane.postcode' not in settings.INSTALLED_APPS:
            self.remove_field('delivery_postcode_lookup')
            self.remove_field('billing_postcode_lookup')
            self.Meta.sections['full_name'] = 'Billing Address'
            self.Meta.sections['delivery_name'] = 'Delivery Address'
            self.update_sections()

        # creating a new order should always have customer not present flag set
        if not edit:
            instance.customer_not_present = True
            instance.status = OrderBase.STATUS_NEW_ORDER

        # basket
        if request.method == 'POST':
            self.basket = Basket(request,
                                 prefix=instance.backend_basket_prefix)
        else:
            self.basket = Basket.restore_from_order(
                instance,
                request=request,
                prefix=instance.backend_basket_prefix,
                persistent=True)
        self.basket.save()
        self.fields['_basket'].widget.order = instance
        self.fields['_basket'].widget.basket = self.basket

        # status
        self.fields['status'].choices = self.get_available_status_choices(
            instance)

        # customer
        self.fields['customer'].queryset = User.objects.filter(
            is_staff=False, is_superuser=False, is_active=True)
        self.fields[
            'customer'].label_from_instance = lambda user: user.full_name_email

        # tracking provider
        if len(settings.TRACKING_PROVIDERS) > 0:
            self.fields['tracking_provider'].choices = [('', '-------')] + [
                (name, name) for name, _ in settings.TRACKING_PROVIDERS
            ]
        else:
            self.remove_field('tracking_provider')
            self.remove_field('tracking_code')
            self.update_sections()

        # initial countries for billing/delivery
        try:
            default_country = Country.objects.get(
                iso=settings.SHOP_DEFAULT_DELIVERY_COUNTRY_ISO)
            self.fields['billing_country'].initial = default_country
            self.fields['delivery_country'].initial = default_country
        except Country.DoesNotExist:
            pass
Example #2
0
    def account_logout(self, request):
        basket = Basket(request)
        auth_logout(request)

        # hook
        shop = get_shop()
        shop.on_customer_logout(request, basket)

        basket.save()

        response = HttpResponseRedirect(reverse('shop.account.index'))
        response.set_cookie('cubaneShopLogin', '0')
        return response
Example #3
0
    def before_save(self, request, cleaned_data, instance, edit):
        # default values
        if not edit:
            from cubane.ishop.views import get_shop
            shop = get_shop()
            instance.customer_not_present = True
            instance.payment_gateway = shop.get_default_payment_gateway()

        # save basket.
        basket = Basket(request, prefix=instance.backend_basket_prefix)
        if not basket.is_empty():
            instance.save_basket(basket)

        # change status
        if request.POST.get('next-status'):
            cleaned_data['status'] = int(request.POST.get('next-status'))
Example #4
0
def shipping_notes(request, secret_id):
    """
    Display for PDF creation of the shipping note/status
    """
    basket = Basket(request)
    order = get_object_or_404(get_order_model(), secret_id=secret_id)

    return {'order': order}
Example #5
0
def index(request):
    """
    Return basket html content.
    """
    if not request.is_ajax():
        raise Http404('Ajax only.')

    # get basket
    prefix = get_basket_prefix(request, request.GET)
    basket = Basket(request, prefix=prefix)
    return HttpResponse(get_basket_html(request, basket))
Example #6
0
def _destroy_basket(request):
    # destroy basket
    basket = Basket(request)
    basket.clear()
    if request.user.is_anonymous():
        request.session[settings.GUEST_USER_SESSION_VAR] = None
Example #7
0
def complete(request):
    """
    (3) Final checkout step, where the order is actually created from the basket.
    """
    basket = Basket(request)

    # redirect back to a previous step if we missed anything...
    next = get_next_checkout_step(request, basket, CurrentPage.COMPLETE())
    if next:
        return HttpResponseRedirect(next)

    # state or county
    if 'state' in basket.billing_address:
        county = basket.billing_address.get('state')
    else:
        county = basket.billing_address.get('county')

    # create account if requested
    if basket.signup:
        # create user account
        md5 = hashlib.md5()
        md5.update(basket.signup.get('email'))
        email = basket.signup.get('email')

        if User.objects.filter(email=email).count() > 0:
            messages.warning(
                request,
                'There is already an account with this email: %s.' % email)
            return HttpResponseRedirect(reverse('shop.account.login'))
        user = User.objects.create(username=md5.hexdigest()[:30],
                                   first_name=basket.signup.get('first_name'),
                                   last_name=basket.signup.get('last_name'),
                                   email=email)

        # replace username with user id and set password
        user.username = unicode(user.id)
        user.set_password(basket.signup.get('password'))
        user.save()

        # create profile
        get_customer_model().objects.create(
            user=user,
            first_name=user.first_name,
            last_name=user.last_name,
            email=user.email,
            title=basket.billing_address.get('title'),
            address1=basket.billing_address.get('address1'),
            address2=basket.billing_address.get('address2'),
            address3=basket.billing_address.get('address3'),
            city=basket.billing_address.get('city'),
            county=county,
            postcode=basket.billing_address.get('postcode'),
            country=basket.billing_address.get('country'),
            telephone=basket.billing_address.get('telephone'),
            newsletter=basket.newsletter)

        # log user in
        login_user_without_password(request, user)
        basket.signup = None
    else:
        if request.user.is_anonymous():
            user = None
        else:
            user = request.user

        # if specified, copy relevant information to customer's profile
        if user != None and basket.update_profile:
            user.first_name = basket.billing_address.get('first_name')
            user.last_name = basket.billing_address.get('last_name')
            user.save()

            customer = get_customer_model().objects.get(user=user)
            customer.address1 = basket.billing_address.get('address1')
            customer.address2 = basket.billing_address.get('address2')
            customer.address3 = basket.billing_address.get('address3')
            customer.city = basket.billing_address.get('city')
            customer.county = county
            customer.postcode = basket.billing_address.get('postcode')
            customer.country = basket.billing_address.get('country')
            customer.telephone = basket.billing_address.get('telephone')
            customer.save()

    # create single order
    order = get_order_model().create_from_basket(request, basket, user)

    # mailchimp
    if request.settings.mailchimp_enabled and basket.newsletter:
        email = basket.billing_address.get('email')
        first_name = basket.billing_address.get('first_name')
        last_name = basket.billing_address.get('last_name')
        person_name = (first_name, last_name)
        merge_vars = {'FNAME': " ".join(person_name)}
        ms = MailSnake(request.settings.mailchimp_api)
        try:
            ms.listSubscribe(id=request.settings.mailchimp_list_id,
                             email_address=email,
                             merge_vars=merge_vars)
        except:
            pass

    # redirect to order status page (payment from there...)
    basket.save()
    return HttpResponseRedirect(
        reverse('shop.order.status', args=[order.secret_id]))
Example #8
0
def delivery_options(request):
    """
    (2) Provide details on delivery options.
    """
    basket = Basket(request)
    if basket.is_empty():
        return HttpResponseRedirect('/')

    # construct delivery options form for entire basket
    items = basket.items
    choices = basket.get_delivery_choices()

    # construct form
    if request.method == 'POST':
        form = DeliveryOptionsFrom(request.POST)
        try:
            option = basket.get_delivery_options()[0]
        except IndexError:
            option = None
    else:
        option = basket.get_delivery_option_or_default()
        form = DeliveryOptionsFrom()

    # configure form with specific delivery options
    form.configure(request, choices, option)
    current_page = CurrentPage.DELIVERY_OPTIONS()

    # if the current open is not within the given set of choices,
    # then change the delivery option to the first one.
    if option:
        if option.id not in [_id for _id, _ in choices]:
            option = basket.get_default_delivery_option()
            basket.set_delivery_option(option)
            basket.save()
            basket = Basket(request)

    # form validation
    if request.method == 'POST' and form.is_valid():
        d = form.cleaned_data

        # get delivery option
        option = DeliveryOption.objects.get(pk=d.get('delivery_option'))

        # configure delivery option
        basket.set_delivery_option(option)

        # next...
        next = next_checkout_step(request, basket, current_page)
        basket.save()
        return next
    else:
        if basket.is_click_and_collect() and request.method == 'POST':
            next = next_checkout_step(request, basket, current_page)
            basket.save()
            return next

    delivery_option = basket.get_delivery_details(
        option) if option != None else None

    return {
        'basket': basket,
        'items': items,
        'form': form,
        'is_click_and_collect': basket.is_click_and_collect(),
        'delivery_option': delivery_option,
        'choices': choices
    }
Example #9
0
def delivery(request):
    """
    (1) Start to checkout by confirming the delivery address.
    The customer is required to login for checkout first (see login).
    """
    basket = Basket(request)
    if basket.is_empty():
        return HttpResponseRedirect('/')

    # if the basket contains collection only products,
    # force click and collect
    if basket.is_collection_only():
        basket.set_click_and_collect(True)

    if request.method == 'POST':
        form = DeliveryAddressFrom(request.POST)
    else:
        billing = basket.billing_address if basket.billing_address else {}
        delivery = basket.delivery_address if basket.delivery_address else {}

        profile = None
        default = {}
        user = request.user
        if not user.is_anonymous():
            try:
                profile = get_customer_model().objects.get(user=user)
                default = {
                    'title': profile.title,
                    'first_name': user.first_name,
                    'last_name': user.last_name,
                    'email': user.email,
                    'telephone': profile.telephone
                }

                if basket.has_billing_address():
                    default.update({
                        'company': profile.company,
                        'address1': profile.address1,
                        'address2': profile.address2,
                        'address3': profile.address3,
                        'city': profile.city,
                        'country': profile.country,
                        'county': profile.county,
                        'postcode': profile.postcode
                    })
            except get_customer_model().DoesNotExist:
                pass
        else:
            default = {
                'email': request.session.get(settings.GUEST_USER_SESSION_VAR),
                'country': 'GB'
            }

        def _get(name, data, fallback=None):
            v = data.get(name)
            if v is None and fallback is not None:
                v = fallback.get(name)
            return v

        form = DeliveryAddressFrom(
            initial={
                'title':
                _get('title', billing, default),
                'first_name':
                _get('first_name', billing, default),
                'last_name':
                _get('last_name', billing, default),
                'email':
                _get('email', billing, default),
                'telephone':
                _get('telephone', billing, default),
                'company':
                _get('company', billing, default),
                'address1':
                _get('address1', billing, default),
                'address2':
                _get('address2', billing, default),
                'address3':
                _get('address3', billing, default),
                'city':
                _get('city', billing, default),
                'country':
                _get('country', billing, default),
                'county':
                _get('county', billing, default),
                'postcode':
                _get('postcode', billing, default),
                'deliver_to':
                DeliveryAddressFrom.DELIVERY_COLLECTION if basket.
                is_click_and_collect(
                ) else DeliveryAddressFrom.DELIVERY_BILLING_ADDRESS,
                'free_name':
                _get('free_name', delivery),
                'delivery_name':
                _get('name', delivery),
                'delivery_company':
                _get('company', delivery),
                'delivery_address1':
                _get('address1', delivery),
                'delivery_address2':
                _get('address2', delivery),
                'delivery_address3':
                _get('address3', delivery),
                'delivery_city':
                _get('city', delivery),
                'delivery_country':
                _get('country', delivery, default),
                'delivery_county':
                _get('county', delivery),
                'delivery_postcode':
                _get('postcode', delivery),
                'finance_option':
                basket.finance_option,
                'loan_deposit':
                basket.loan_deposit,
                'newsletter':
                basket.newsletter,
                'terms':
                basket.terms,
                'special_req':
                basket.special_req,
                'survey':
                basket.survey,
                'signup':
                basket.signup != None,
                'password':
                basket.signup.get('password') if basket.signup else None,
                'password_confirm':
                basket.signup.get('password') if basket.signup else None,
                'update_profile':
                basket.update_profile
            })

    form.configure(request, basket)
    current_page = CurrentPage.DELIVERY_ADDRESS()

    if request.method == 'POST' and form.is_valid():
        d = form.cleaned_data

        if 'email' in d:
            email = d.get('email')
        else:
            email = request.user.email

        # keep initial address information if we are not allowed to change the
        # billing address
        if not basket.can_edit_billing_address:
            for field in [
                    'company', 'address1', 'address2', 'address3', 'city',
                    'country', 'county', 'postcode'
            ]:
                d[field] = basket.billing_address.get(field)

        # save billing address
        basket.set_billing_address(title=d.get('title'),
                                   first_name=d.get('first_name'),
                                   last_name=d.get('last_name'),
                                   email=email,
                                   telephone=d.get('telephone'),
                                   company=d.get('company'),
                                   address1=d.get('address1'),
                                   address2=d.get('address2'),
                                   address3=d.get('address3'),
                                   city=d.get('city'),
                                   country=d.get('country'),
                                   county=d.get('county'),
                                   postcode=d.get('postcode'))

        # get delivery method
        deliver_to = d.get('deliver_to',
                           DeliveryAddressFrom.DELIVERY_BILLING_ADDRESS)

        basket.set_click_and_collect(
            deliver_to == DeliveryAddressFrom.DELIVERY_COLLECTION
            or basket.is_collection_only())
        basket.set_free_delivery_to(False)

        if deliver_to == DeliveryAddressFrom.FREE_DELIVERY_TO:
            location = basket.get_normalized_free_delivery_to_address()

            basket.set_delivery_address(name=d.get('delivery_free_name'),
                                        company=location.get('title'),
                                        address1=location.get('address1'),
                                        address2=location.get('address2'),
                                        address3=location.get('address3'),
                                        city=location.get('city'),
                                        country=location.get('country'),
                                        county=location.get('county'),
                                        postcode=location.get('postcode'))
            basket.set_free_delivery_to(True)
        elif deliver_to == DeliveryAddressFrom.DELIVERY_BILLING_ADDRESS:
            # deliver to my billing address
            basket.set_delivery_address(
                name='%s %s' % (d.get('first_name'), d.get('last_name')),
                company=d.get('company'),
                address1=d.get('address1'),
                address2=d.get('address2'),
                address3=d.get('address3'),
                city=d.get('city'),
                country=d.get('country'),
                county=d.get('county'),
                postcode=d.get('postcode'))
        elif deliver_to == DeliveryAddressFrom.DELIVERY_NEW_ADDRESS:
            # enter new delivery address
            basket.set_delivery_address(name=d.get('delivery_name'),
                                        company=d.get('delivery_company'),
                                        address1=d.get('delivery_address1'),
                                        address2=d.get('delivery_address2'),
                                        address3=d.get('delivery_address3'),
                                        city=d.get('delivery_city'),
                                        country=d.get('delivery_country'),
                                        county=d.get('delivery_county'),
                                        postcode=d.get('delivery_postcode'))

            # create a new record for the customer's profile
            if not request.user.is_anonymous():
                n = DeliveryAddress.objects.filter(
                    user=request.user,
                    address1=d.get('delivery_address1'),
                    address2=d.get('delivery_address2'),
                    address3=d.get('delivery_address3'),
                    city=d.get('delivery_city'),
                    country=d.get('delivery_country'),
                    county=d.get('delivery_county'),
                    postcode=d.get('delivery_postcode')).count()

                if n == 0:
                    address = DeliveryAddress()
                    address.user = request.user
                    address.name = d.get('delivery_name')
                    address.company = d.get('delivery_company')
                    address.address1 = d.get('delivery_address1')
                    address.address2 = d.get('delivery_address2')
                    address.address3 = d.get('delivery_address3')
                    address.city = d.get('delivery_city')
                    address.country = d.get('delivery_country')
                    address.county = d.get('delivery_county')
                    address.postcode = d.get('delivery_postcode')
                    address.save()
        else:
            if not basket.is_click_and_collect():
                # delivery to one of my delivery addresses taken from my profile
                delivery_address = DeliveryAddress.objects.get(
                    user=request.user, pk=deliver_to)
                basket.set_delivery_address(name=delivery_address.name,
                                            company=delivery_address.company,
                                            address1=delivery_address.address1,
                                            address2=delivery_address.address2,
                                            address3=delivery_address.address3,
                                            city=delivery_address.city,
                                            country=delivery_address.country,
                                            county=delivery_address.county,
                                            postcode=delivery_address.postcode)

        is_loan_available = settings.SHOP_LOAN_ENABLED and 'finance_option' in d and 'loan_deposit' in d

        if is_loan_available and deliver_to == DeliveryAddressFrom.DELIVERY_NEW_ADDRESS:
            # deliver to my billing address as it is required by law if finance option is chosen
            if d.get('finance_option'):
                basket.set_delivery_address(
                    name='%s %s' % (d.get('first_name'), d.get('last_name')),
                    company=d.get('company'),
                    address1=d.get('address1'),
                    address2=d.get('address2'),
                    address3=d.get('address3'),
                    city=d.get('city'),
                    country=d.get('country'),
                    county=d.get('county'),
                    postcode=d.get('postcode'))

        # loan application
        if is_loan_available:
            basket.set_finance_option(d.get('finance_option'))
            basket.set_loan_deposit(d.get('loan_deposit'))
        else:
            basket.set_finance_option(None)
            basket.set_loan_deposit(None)

        # newsletter
        if request.settings.mailchimp_enabled and 'newsletter' in d and d.get(
                'newsletter'):
            basket.newsletter = True

        # terms and conditions
        if request.settings.has_terms and 'terms' in d and d.get('terms'):
            basket.terms = True

        # special requiremenets
        basket.special_req = d.get('special_req')

        # survey
        basket.survey = d.get('survey') if 'survey' in d else None

        # signup?
        if d.get('signup', False) == True:
            basket.set_signup(email=d.get('email'),
                              first_name=d.get('first_name'),
                              last_name=d.get('last_name'),
                              password=d.get('password'))
        else:
            basket.clear_signup()

        # default delivery address?
        if 'update_profile' in d and d.get('update_profile'):
            basket.update_profile = True

        # next...
        next = next_checkout_step(request, basket, current_page)
        basket.save()
        return next

    # generate list of available delivery addresses from customer's profile
    if request.user.is_anonymous():
        delivery_addresses = []
    else:
        delivery_addresses = [{
            'id': i,
            'iso': addr.country.iso
        } for i, addr in enumerate(request.user.delivery_addresses.all(),
                                   start=3)]

    return {
        'basket': basket,
        'form': form,
        'delivery_addresses': to_json(delivery_addresses)
    }
Example #10
0
def login(request):
    """
    Provide ability to choose to login with an existing account, create a new
    account or just providing an email address for a guest checkout.
    """
    basket = Basket(request)
    if basket.is_empty():
        return HttpResponseRedirect('/')

    login_form = CustomerLoginForm(request=request, prefix='customer')
    guest_form = GuestLoginForm(prefix='guest')
    form = None

    if request.method == 'POST':
        if request.POST.get('password_forgotten', None) != None:
            login_form = PasswordForgottenForm(request.POST, prefix='customer')
            form = login_form
        elif request.POST.get('customer', None) != None:
            login_form = CustomerLoginForm(request.POST,
                                           request=request,
                                           prefix='customer')
            form = login_form
        else:
            guest_form = GuestLoginForm(request.POST, prefix='guest')
            form = guest_form

    if form != None and form.is_valid():
        if isinstance(form, PasswordForgottenForm):
            email = form.cleaned_data.get('email')
            if request.context.password_forgotten(request, email):
                messages.success(
                    request, 'Your new password has been send to: %s.' % email)
            else:
                messages.error(
                    request,
                    'We were not able to send an email to: %s' % email)
            return HttpResponseRedirect(reverse('shop.order.login'))
        elif isinstance(form, CustomerLoginForm):
            user = form.get_user()
            if user.is_authenticated():
                auth_login(request, user)
                request.session[settings.GUEST_USER_SESSION_VAR] = ''
                response = HttpResponseRedirect(reverse('shop.order.delivery'))
                response.set_cookie('cubaneShopLogin', '1')

                # hook
                shop = get_shop()
                shop.on_customer_login(request, basket, user)

                return response
        else:
            if request.user.is_authenticated():
                auth_logout(request)

                # hook
                shop = get_shop()
                shop.on_customer_logout(request, basket)
                basket.save()

            request.session[
                settings.GUEST_USER_SESSION_VAR] = form.cleaned_data.get(
                    'email')
            return HttpResponseRedirect(reverse('shop.order.delivery'))

    return {
        'login_form': login_form,
        'guest_form': guest_form,
        'basket': basket
    }
Example #11
0
class OrderForm(BaseModelForm):
    ADDRESS_NAMES = [
        'company', 'address1', 'address2', 'address3', 'city', 'county',
        'postcode', 'country'
    ]

    class Meta:
        model = get_order_model()
        fields = [
            # status
            'status',

            # tracking
            'tracking_provider',
            'tracking_code',

            # customer
            'customer',
            'email',
            'telephone',

            # details
            'special_requirements',

            # billing
            'billing_postcode_lookup',
            'full_name',
            'billing_company',
            'billing_address1',
            'billing_address2',
            'billing_address3',
            'billing_city',
            'billing_county',
            'billing_postcode',
            'billing_country',

            # delivery
            'delivery_postcode_lookup',
            'delivery_name',
            'delivery_company',
            'delivery_address1',
            'delivery_address2',
            'delivery_address3',
            'delivery_city',
            'delivery_county',
            'delivery_postcode',
            'delivery_country'
        ]
        tabs = [
            {
                'title': 'Line Items',
                'fields': ['_basket']
            },
            {
                'title':
                'Status and Tracking',
                'fields': [
                    # status
                    'status',

                    # tracking
                    'tracking_provider',
                    'tracking_code'
                ]
            },
            {
                'title':
                'Details',
                'fields': [
                    # customer
                    'customer',
                    'email',
                    'telephone',

                    # details
                    'special_requirements',

                    # billing
                    'billing_postcode_lookup',
                    'full_name',
                    'billing_company',
                    'billing_address1',
                    'billing_address2',
                    'billing_address3',
                    'billing_city',
                    'billing_county',
                    'billing_postcode',
                    'billing_country',

                    # delivery
                    'delivery_postcode_lookup',
                    'delivery_name',
                    'delivery_company',
                    'delivery_address1',
                    'delivery_address2',
                    'delivery_address3',
                    'delivery_city',
                    'delivery_county',
                    'delivery_postcode',
                    'delivery_country'
                ]
            }
        ]
        sections = {
            'status': 'Order Status',
            'tracking_provider': 'Order Delivery Tracking',
            'customer': 'Customer Information',
            'special_requirements': 'Customer Details',
            'billing_postcode_lookup': 'Billing Address',
            'delivery_postcode_lookup': 'Delivery Address',
        }

    _basket = BasketField()

    customer = BrowseCustomerField(
        required=False,
        help_text=
        'The registered customer of this order; otherwise this order is a Guest Checkout.'
    )

    tracking_provider = forms.ChoiceField(
        label='Tracking Provider',
        choices=[],
        required=False,
        help_text=
        'Choose the tracking provider that is tracking the delivery of this order.'
    )

    billing_postcode_lookup = PostcodeLookupField(
        label='Find Address',
        address1='id_billing_address1',
        address2='id_billing_address2',
        address3='id_billing_address3',
        address4=None,
        locality=None,
        city='id_billing_city',
        county='id_billing_county',
        postcode='id_billing_postcode')

    delivery_postcode_lookup = PostcodeLookupField(
        label='Find Address',
        address1='id_delivery_address1',
        address2='id_delivery_address2',
        address3='id_delivery_address3',
        address4=None,
        locality=None,
        city='id_delivery_city',
        county='id_delivery_county',
        postcode='id_delivery_postcode')

    def get_available_status_choices(self, instance):
        """
        Return list of available status choices that are applicable for the given order.
        """
        choices = OrderBase.BACKEND_STATUS_CHOICES_FILTER

        new_choices = []
        if instance.click_and_collect:
            for choice in choices:
                if not choice[
                        0] == OrderBase.STATUS_PARTIALLY_SHIPPED and not choice[
                            0] == OrderBase.STATUS_SHIPPED:
                    new_choices.append(choice)
        else:
            for choice in choices:
                if not choice[0] == OrderBase.STATUS_READY_TO_COLLECT:
                    new_choices.append(choice)

        if instance.customer_not_present:
            # created via backend (customer not present)
            new_choices = filter(
                lambda c: c[0] in OrderBase.CUSTOMER_NOT_PRESENT_STATUS,
                new_choices)
        elif instance.is_invoice:
            # pay by invoice orders do not have any payment-related states
            new_choices = filter(lambda c: c[0] in OrderBase.INVOICE_STATUS,
                                 new_choices)
        elif instance.is_zero_amount_checkout:
            # zero amount checkout do not have payment-related status
            new_choices = filter(
                lambda c: c[0] in OrderBase.ZERO_AMOUNT_CHECKOUT_STATUS,
                new_choices)
        else:
            # regular non-invoice orders do not have invoice-related status
            new_choices = filter(lambda c: c[0] in OrderBase.PAYMENT_STATUS,
                                 new_choices)

        return new_choices

    def clean(self):
        d = super(OrderForm, self).clean()
        click_and_collect = self.basket.click_and_collect

        # clean billing address
        clean_company(self, d, 'billing_company')
        clean_address_line(self, d, 'billing_address1')
        clean_address_line(self, d, 'billing_address2')
        clean_address_line(self, d, 'billing_address3')
        clean_city(self, d, 'billing_city')
        clean_county(self, d, 'billing_county', 'billing_country')
        clean_postcode(self, d, 'billing_postcode', 'billing_country')

        # clean delivery address
        if not click_and_collect:
            # setup default values for delivery address based on billing address
            for fieldname in self.ADDRESS_NAMES:
                delivery_fieldname = 'delivery_%s' % fieldname
                if not d.get(delivery_fieldname):
                    self.cleaned_data[delivery_fieldname] = d[
                        delivery_fieldname] = d.get('billing_%s' % fieldname)

            # clean delivery address
            clean_company(self, d, 'delivery_company')
            clean_address_line(self, d, 'delivery_address1')
            clean_address_line(self, d, 'delivery_address2')
            clean_address_line(self, d, 'delivery_address3')
            clean_city(self, d, 'delivery_city')
            clean_county(self, d, 'delivery_county', 'delivery_country')
            clean_postcode(self, d, 'delivery_postcode', 'delivery_country')

        # make delivery address fields required if not click and collect
        if not click_and_collect:
            address1 = d.get('delivery_address1')
            city = d.get('delivery_city')
            postcode = d.get('delivery_postcode')
            country = d.get('delivery_country')

            if not address1:
                self.field_error('delivery_address1', self.ERROR_REQUIRED)
            if not city: self.field_error('delivery_city', self.ERROR_REQUIRED)
            if not postcode:
                self.field_error('delivery_postcode', self.ERROR_REQUIRED)
            if not country:
                self.field_error('delivery_country', self.ERROR_REQUIRED)

        # verify that we do not end up with an empty basket
        basket = Basket(self._request,
                        prefix=self._instance.backend_basket_prefix)
        if basket.is_empty():
            from cubane.lib.mail import trigger_exception_email
            trigger_exception_email(self._request,
                                    'Cannot save empty order.',
                                    data={
                                        'form':
                                        self,
                                        'formdata':
                                        d,
                                        'basket:':
                                        basket.save_to_dict(use_session=False)
                                    })
            raise forms.ValidationError('Cannot save empty order.')

        return d

    def configure(self, request, instance=None, edit=True):
        super(OrderForm, self).configure(request, instance, edit)

        if 'cubane.postcode' not in settings.INSTALLED_APPS:
            self.remove_field('delivery_postcode_lookup')
            self.remove_field('billing_postcode_lookup')
            self.Meta.sections['full_name'] = 'Billing Address'
            self.Meta.sections['delivery_name'] = 'Delivery Address'
            self.update_sections()

        # creating a new order should always have customer not present flag set
        if not edit:
            instance.customer_not_present = True
            instance.status = OrderBase.STATUS_NEW_ORDER

        # basket
        if request.method == 'POST':
            self.basket = Basket(request,
                                 prefix=instance.backend_basket_prefix)
        else:
            self.basket = Basket.restore_from_order(
                instance,
                request=request,
                prefix=instance.backend_basket_prefix,
                persistent=True)
        self.basket.save()
        self.fields['_basket'].widget.order = instance
        self.fields['_basket'].widget.basket = self.basket

        # status
        self.fields['status'].choices = self.get_available_status_choices(
            instance)

        # customer
        self.fields['customer'].queryset = User.objects.filter(
            is_staff=False, is_superuser=False, is_active=True)
        self.fields[
            'customer'].label_from_instance = lambda user: user.full_name_email

        # tracking provider
        if len(settings.TRACKING_PROVIDERS) > 0:
            self.fields['tracking_provider'].choices = [('', '-------')] + [
                (name, name) for name, _ in settings.TRACKING_PROVIDERS
            ]
        else:
            self.remove_field('tracking_provider')
            self.remove_field('tracking_code')
            self.update_sections()

        # initial countries for billing/delivery
        try:
            default_country = Country.objects.get(
                iso=settings.SHOP_DEFAULT_DELIVERY_COUNTRY_ISO)
            self.fields['billing_country'].initial = default_country
            self.fields['delivery_country'].initial = default_country
        except Country.DoesNotExist:
            pass
Example #12
0
    def clean(self):
        d = super(OrderForm, self).clean()
        click_and_collect = self.basket.click_and_collect

        # clean billing address
        clean_company(self, d, 'billing_company')
        clean_address_line(self, d, 'billing_address1')
        clean_address_line(self, d, 'billing_address2')
        clean_address_line(self, d, 'billing_address3')
        clean_city(self, d, 'billing_city')
        clean_county(self, d, 'billing_county', 'billing_country')
        clean_postcode(self, d, 'billing_postcode', 'billing_country')

        # clean delivery address
        if not click_and_collect:
            # setup default values for delivery address based on billing address
            for fieldname in self.ADDRESS_NAMES:
                delivery_fieldname = 'delivery_%s' % fieldname
                if not d.get(delivery_fieldname):
                    self.cleaned_data[delivery_fieldname] = d[
                        delivery_fieldname] = d.get('billing_%s' % fieldname)

            # clean delivery address
            clean_company(self, d, 'delivery_company')
            clean_address_line(self, d, 'delivery_address1')
            clean_address_line(self, d, 'delivery_address2')
            clean_address_line(self, d, 'delivery_address3')
            clean_city(self, d, 'delivery_city')
            clean_county(self, d, 'delivery_county', 'delivery_country')
            clean_postcode(self, d, 'delivery_postcode', 'delivery_country')

        # make delivery address fields required if not click and collect
        if not click_and_collect:
            address1 = d.get('delivery_address1')
            city = d.get('delivery_city')
            postcode = d.get('delivery_postcode')
            country = d.get('delivery_country')

            if not address1:
                self.field_error('delivery_address1', self.ERROR_REQUIRED)
            if not city: self.field_error('delivery_city', self.ERROR_REQUIRED)
            if not postcode:
                self.field_error('delivery_postcode', self.ERROR_REQUIRED)
            if not country:
                self.field_error('delivery_country', self.ERROR_REQUIRED)

        # verify that we do not end up with an empty basket
        basket = Basket(self._request,
                        prefix=self._instance.backend_basket_prefix)
        if basket.is_empty():
            from cubane.lib.mail import trigger_exception_email
            trigger_exception_email(self._request,
                                    'Cannot save empty order.',
                                    data={
                                        'form':
                                        self,
                                        'formdata':
                                        d,
                                        'basket:':
                                        basket.save_to_dict(use_session=False)
                                    })
            raise forms.ValidationError('Cannot save empty order.')

        return d
Example #13
0
    def account_login(self, request):
        basket = Basket(request)
        checkout = request.GET.get('checkout', False) == '1'
        initial = {
            'checkout': checkout
        }

        login_form = CustomerLoginForm(request=request, prefix='customer', initial=initial)
        guest_form = NewCustomerForm(prefix='guest', initial=initial)
        guest_form.configure(request)
        form = None

        if request.method == 'POST':
            if request.POST.get('password_forgotten', None) != None:
                login_form = PasswordForgottenForm(request.POST, prefix='customer')
                form = login_form
            elif request.POST.get('customer', None) != None:
                login_form = CustomerLoginForm(request.POST, request=request, prefix='customer')
                form = login_form
            else:
                guest_form = NewCustomerForm(request.POST, prefix='guest')
                guest_form.configure(request)
                form = guest_form

        if form != None and form.is_valid():
            if isinstance(form, PasswordForgottenForm):
                email = form.cleaned_data.get('email')
                checkout = form.cleaned_data.get('checkout', '0')

                if request.context.password_forgotten(request, email):
                    messages.success(request, 'Your new password has been sent to \'%s\'.' % email)
                else:
                    messages.error(request, 'We were not able to recognise the email address \'%s\'. Please make sure that you entered your email address correctly.' % email)

                return HttpResponseRedirect(reverse('shop.account.login') + '?checkout=%s' % checkout)
            elif isinstance(form, CustomerLoginForm):
                user = form.get_user()
                checkout = form.cleaned_data.get('checkout', '0')

                if user.is_authenticated():
                    auth_login(request, user)

                    if checkout:
                        response = HttpResponseRedirect(reverse('shop.order.delivery'))
                    else:
                        response = HttpResponseRedirect(reverse('shop.account.index'))

                    response.set_cookie('cubaneShopLogin', '1')

                    # hook
                    shop = get_shop()
                    shop.on_customer_login(request, basket, user)

                    return response
            else:
                checkout = form.cleaned_data.get('checkout', '0')

                if request.user.is_authenticated():
                    auth_logout(request)

                    # hook
                    shop = get_shop()
                    shop.on_customer_logout(request, basket)
                    basket.save()

                request.session[settings.SIGNUP_EMAIL_SESSION_VAR] = form.cleaned_data['email']

                return HttpResponseRedirect(reverse('shop.account.signup') + '?checkout=%s' % checkout)

        request.session.set_test_cookie()

        return {
            'account_section': True,
            'login_form': login_form,
            'guest_form': guest_form,
        }
Example #14
0
def update(request):
    """
    Update basket. This may also trigger "continue shopping" and "checkout".
    """
    # get prefix
    prefix = get_basket_prefix(request, request.POST)

    # get basket
    basket = Basket(request, prefix=prefix)
    return_url = get_return_url(request)

    # keep track of removed items
    removed_items = []

    def add_removed_item(item):
        removed_items.append(item)

    if not basket.is_frozen:
        # update quantity
        for item in list(basket.items):
            k = 'qty_%s' % item.hash
            if k in request.POST:
                try:
                    qty = int(request.POST.get(k, 0))
                except ValueError:
                    qty = 0

                removed = basket.update_quantity_by_hash(item.hash, qty)
                if removed:
                    add_removed_item(item)

        # remove item
        item_hash = request.POST.get('remove_basket_item', '')
        if item_hash != '':
            item = basket.remove_item_by_hash(item_hash)
            if item:
                add_removed_item(item)

        # voucher
        if 'voucher-code' in request.POST:
            voucher_code = request.POST.get('voucher-code')
            if voucher_code:
                voucher_code = voucher_code.upper()
            if voucher_code:
                if voucher_code != basket.get_voucher_code():
                    # add voucher code to basket
                    if not basket.set_voucher(voucher_code):
                        if not request.is_ajax():
                            messages.error(
                                request,
                                'Expired or unrecognised voucher code.')
            else:
                basket.remove_voucher()

        # delivery country
        if 'country_iso' in request.POST:
            try:
                country = Country.objects.get(
                    iso=request.POST.get('country_iso'))
                basket.set_delivery_country(country)
            except Country.DoesNotExist:
                pass

        # custom total (staff only)
        if request.user.is_staff or request.user.is_superuser:
            if 'custom-total' in request.POST:
                custom_total = request.POST.get('custom-total')
                if custom_total == '':
                    basket.clear_custom_total()
                else:
                    custom_total = Decimal(custom_total)
                    basket.set_custom_total(custom_total)

    # click and collect
    if 'click_and_collect' in request.POST:
        basket.set_click_and_collect(
            request.POST.get('click_and_collect') in ['true', 'on'])

    # delivery option
    option_id = request.POST.get('delivery_option_id', None)
    delivery_option_details = None
    if option_id:
        try:
            option = DeliveryOption.objects.get(pk=option_id, enabled=True)
            delivery_option_details = basket.get_delivery_details(option)
            basket.set_delivery_option(option)
        except DeliveryOption.DoesNotExist:
            pass

    # processing state (backend only)
    if request.user.is_staff or request.user.is_superuser:
        for item in list(basket.items):
            k = 'processed_%s' % item.hash
            if k in request.POST:
                processed = request.POST.get(k, 'off') == 'on'
                basket.update_processed_by_hash(item.hash, processed)

    # save changes to basket
    basket.save()

    # ajax?
    if request.is_ajax():
        basket = Basket(request, prefix=prefix)
        return to_json_response({
            'success':
            True,
            'prefix':
            basket.prefix,
            'html':
            get_basket_html(request, basket),
            'delivery':
            get_delivery_option_details_html(request, delivery_option_details),
            'is_collection_only':
            basket.is_collection_only(),
            'finance_options':
            [option.to_dict() for option in basket.get_finance_options()],
            'removed': [item.to_ga_dict() for item in removed_items]
        })

    # next
    action = request.POST.get('action', 'update')
    if action == 'continue':
        return HttpResponseRedirect(return_url)
    elif action == 'checkout':
        return HttpResponseRedirect(reverse('shop.order.delivery'))
    else:
        return HttpResponseRedirect(return_url)
Example #15
0
def add(request):
    """
    Add given product to the customer's basket and redirect to the basket page.
    """
    product = get_product_or_404(request)

    return_url = get_return_url(request)

    form = AddToBasketForm(request.POST, request=request, product=product)

    variant = ''
    quantity = 0
    price = 0
    prefix = None

    if form.is_valid():
        d = form.cleaned_data

        variety_options = form.get_variety_options()
        variety_option_labels = form.get_variety_option_labels(variety_options)
        variant = ', '.join([option.title for option in variety_options])
        quantity = form.get_quantity()
        prefix = get_basket_prefix(request, d)

        # add to basket
        basket = Basket(request, prefix=prefix)
        item = basket.add_item(product,
                               variety_options,
                               quantity,
                               custom=None,
                               labels=variety_option_labels)

        if item:
            price = item.total_product
        else:
            messages.error(
                request,
                "Please note that the product '%s' cannot be added to basket."
                % product.title)

        # alert for non-returnable products
        if product.non_returnable:
            messages.warning(
                request,
                "Please note that the product '%s' cannot be returned." %
                product.title)

        # hook
        shop = get_shop()
        shop.on_basket_added(request, basket, product, variety_options,
                             quantity)
        basket.save()
        errors = False
    else:
        errors = form.errors

    if request.is_ajax():
        basket = Basket(request, prefix=prefix)
        return to_json_response({
            'success':
            True,
            'html':
            get_basket_html(request, basket),
            'errors':
            errors,
            'prefix':
            basket.prefix,
            'added':
            product.to_ga_dict({
                'variant': variant,
                'quantity': quantity,
                'price': price
            })
        })
    else:
        return HttpResponseRedirect(return_url)
Example #16
0
    def google_products(self, request):
        def prettify_xml(elem):
            """
            Return a pretty-printed XML string for the Element.
            """
            rough_string = tostring(elem)
            reparsed = minidom.parseString(rough_string)
            return reparsed.toprettyxml(indent='\t').encode('utf-8', 'replace')

        products = get_product_model().objects.filter(feed_google=True)
        root = Element('rss')
        root.attrib['xmlns:g'] = 'http://base.google.com/ns/1.0'
        root.attrib['version'] = '2.0'
        channel = SubElement(root, 'channel')
        title = SubElement(channel, 'title')
        title.text = request.settings.name
        link = SubElement(channel, 'link')
        link.text = settings.DOMAIN_NAME
        description = SubElement(channel, 'description')

        for p in products:
            # availability
            if p.is_available and not p.pre_order:
                txt_availability = 'in stock'
            elif p.pre_order:
                txt_availability = 'preorder'
            else:
                txt_availability = 'out of stock'

            # determine delivery charge by placing the product onto the basket
            basket = Basket()
            basket.add_item(p, None, 1)
            delivery_charge = basket.delivery

            # determine feed item attributes
            txt_id = unicode(p.id)
            txt_title = clean_unicode(p.title).strip()
            txt_link = p.get_absolute_url()
            txt_description = text_from_html(p.description, 5000)
            txt_condition = 'new'
            txt_price = '%.2f GBP' % p.price
            txt_google_category = p.category.google_product_category if p.category and p.category.google_product_category else None
            txt_category = p.category.get_taxonomy_path(
            ) if p.category else None
            txt_country = 'GB'
            txt_delivery_price = '%s %s' % (delivery_charge, 'GBP')
            txt_barcode = p.barcode.strip() if p.barcode else None
            txt_part_number = p.part_number.strip() if p.part_number else None
            txt_brand = p.get_brand_title()

            # create item
            item = SubElement(channel, 'item')

            # id
            _id = SubElement(item, 'g:id')
            _id.text = txt_id

            # title
            title = SubElement(item, 'title')
            title.text = txt_title

            # link/url
            link = SubElement(item, 'link')
            link.text = txt_link

            # main text
            description = SubElement(item, 'description')
            description.text = txt_description

            # condition
            condition = SubElement(item, 'g:condition')
            condition.text = txt_condition

            # price
            price = SubElement(item, 'g:price')
            price.text = txt_price

            # availability
            availability = SubElement(item, 'g:availability')
            availability.text = txt_availability

            # google shopping category
            if txt_google_category:
                gcategory = SubElement(item, 'g:google_product_category')
                gcategory.text = txt_google_category

            # product type
            if txt_category:
                category = SubElement(item, 'g:product_type')
                category.text = txt_category

            # shipping
            shipping = SubElement(item, 'g:shipping')

            # country
            country = SubElement(shipping, 'g:country')
            country.text = txt_country

            # delivery price
            delivery_price = SubElement(shipping, 'g:price')
            delivery_price.text = txt_delivery_price

            # barcode, must be a valid UPC-A (GTIN-12), EAN/JAN (GTIN-13)
            # or GTIN-14, so we need to have at least 12 characters.
            if txt_barcode:
                gtin = SubElement(item, 'g:gtin')
                gtin.text = txt_barcode

            # part number
            if txt_part_number:
                _mpn = SubElement(item, 'g:mpn')
                _mpn.text = txt_part_number

            # brand
            if txt_brand:
                brand = SubElement(item, 'g:brand')
                brand.text = txt_brand

            # image
            if p.image:
                image = SubElement(item, 'g:image_link')
                image.text = p.image.large_url

            # additional images
            if len(p.gallery) > 0:
                for m in p.gallery[:10]:
                    additional_image_link = SubElement(
                        item, 'g:additional_image_link')
                    additional_image_link.text = m.large_url

        # get temp. filename
        f = NamedTemporaryFile(delete=False)
        tmp_filename = f.name
        f.close()

        # create tmp file (utf-8)
        f = open(tmp_filename, 'w+b')
        f.write(prettify_xml(root))
        f.seek(0)

        # send response
        filename = 'google_products_%s.xml' % datetime.date.today().strftime(
            '%d_%m_%Y')
        response = HttpResponse(FileWrapper(f), content_type='text/plain')
        response['Content-Disposition'] = 'attachment; filename=%s' % filename
        return response
Example #17
0
    def basket_editor(self, request):
        prefix = request.GET.get('prefix')
        basket = Basket(request, prefix=prefix)

        return {'basket': basket}