Merge branch 'release/3.4.0'
This commit is contained in:
commit
adf275331c
@ -2,7 +2,7 @@ from django.contrib import admin
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
|
||||||
from .models import Address, User
|
from .models import User
|
||||||
from .forms import AccountCreateForm, AccountUpdateForm
|
from .forms import AccountCreateForm, AccountUpdateForm
|
||||||
|
|
||||||
class UserAdmin(UserAdmin):
|
class UserAdmin(UserAdmin):
|
||||||
@ -12,5 +12,4 @@ class UserAdmin(UserAdmin):
|
|||||||
list_display = ['email', 'username',]
|
list_display = ['email', 'username',]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Address)
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|||||||
@ -9,3 +9,4 @@ class AccountsConfig(AppConfig):
|
|||||||
from .signals import (
|
from .signals import (
|
||||||
user_saved
|
user_saved
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -2,21 +2,7 @@ from django import forms
|
|||||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
||||||
from allauth.account.forms import SignupForm
|
from allauth.account.forms import SignupForm
|
||||||
from captcha.fields import CaptchaField
|
from captcha.fields import CaptchaField
|
||||||
from .models import Address, User
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
class AddressForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Address
|
|
||||||
fields = (
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'street_address_1',
|
|
||||||
'street_address_2',
|
|
||||||
'city',
|
|
||||||
'state',
|
|
||||||
'postal_code',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AccountCreateForm(UserCreationForm):
|
class AccountCreateForm(UserCreationForm):
|
||||||
@ -32,24 +18,41 @@ class AccountUpdateForm(UserChangeForm):
|
|||||||
'first_name',
|
'first_name',
|
||||||
'last_name',
|
'last_name',
|
||||||
'email',
|
'email',
|
||||||
'default_shipping_address',
|
'shipping_street_address_1',
|
||||||
'addresses',
|
'shipping_street_address_2',
|
||||||
|
'shipping_city',
|
||||||
|
'shipping_state',
|
||||||
|
'shipping_postal_code',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomerUpdateForm(forms.ModelForm):
|
class CustomerUpdateForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
class Meta:
|
||||||
super().__init__(*args, **kwargs)
|
model = User
|
||||||
self.fields['default_shipping_address'].queryset = kwargs['instance'].addresses
|
fields = (
|
||||||
|
'email',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerShippingAddressUpdateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = (
|
fields = (
|
||||||
'first_name',
|
'first_name',
|
||||||
'last_name',
|
'last_name',
|
||||||
'email',
|
'shipping_street_address_1',
|
||||||
'default_shipping_address',
|
'shipping_street_address_2',
|
||||||
|
'shipping_city',
|
||||||
|
'shipping_state',
|
||||||
|
'shipping_postal_code',
|
||||||
)
|
)
|
||||||
|
labels = {
|
||||||
|
'shipping_street_address_1': 'Street line 1',
|
||||||
|
'shipping_street_address_2': 'Street line 2',
|
||||||
|
'shipping_city': 'City',
|
||||||
|
'shipping_state': 'State',
|
||||||
|
'shipping_postal_code': 'ZIP code',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class UserSignupForm(SignupForm):
|
class UserSignupForm(SignupForm):
|
||||||
@ -62,3 +65,4 @@ class UserSignupForm(SignupForm):
|
|||||||
widget=forms.TextInput(attrs={'placeholder': 'Last name'})
|
widget=forms.TextInput(attrs={'placeholder': 'Last name'})
|
||||||
)
|
)
|
||||||
captcha = CaptchaField()
|
captcha = CaptchaField()
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 02:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0002_address_accounts_address_all_key'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='shipping_city',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='shipping_postal_code',
|
||||||
|
field=models.CharField(blank=True, max_length=20),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='shipping_state',
|
||||||
|
field=models.CharField(blank=True, choices=[('AL', 'Alabama'), ('AK', 'Alaska'), ('AS', 'American Samoa'), ('AZ', 'Arizona'), ('AR', 'Arkansas'), ('AA', 'Armed Forces Americas'), ('AE', 'Armed Forces Europe'), ('AP', 'Armed Forces Pacific'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DE', 'Delaware'), ('DC', 'District of Columbia'), ('FM', 'Federated States of Micronesia'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('IA', 'Iowa'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('ME', 'Maine'), ('MH', 'Marshall Islands'), ('MD', 'Maryland'), ('MA', 'Massachusetts'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MS', 'Mississippi'), ('MO', 'Missouri'), ('MT', 'Montana'), ('NE', 'Nebraska'), ('NV', 'Nevada'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NY', 'New York'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('MP', 'Northern Mariana Islands'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PW', 'Palau'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VT', 'Vermont'), ('VI', 'Virgin Islands'), ('VA', 'Virginia'), ('WA', 'Washington'), ('WV', 'West Virginia'), ('WI', 'Wisconsin'), ('WY', 'Wyoming')], max_length=2),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='shipping_street_address_1',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='shipping_street_address_2',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 02:56
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def copy_default_address_to_user(apps, schema_editor):
|
||||||
|
User = apps.get_model("accounts", "User")
|
||||||
|
|
||||||
|
for user in User.objects.all():
|
||||||
|
if user.default_shipping_address:
|
||||||
|
user.shipping_street_address_1 = user.default_shipping_address.street_address_1
|
||||||
|
user.shipping_street_address_2 = user.default_shipping_address.street_address_2
|
||||||
|
user.shipping_city = user.default_shipping_address.city
|
||||||
|
user.shipping_state = user.default_shipping_address.state
|
||||||
|
user.shipping_postal_code = user.default_shipping_address.postal_code
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('accounts', '0003_user_shipping_city_user_shipping_postal_code_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(copy_default_address_to_user)
|
||||||
|
]
|
||||||
29
accounts/migrations/0005_remove_user_addresses_and_more.py
Normal file
29
accounts/migrations/0005_remove_user_addresses_and_more.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 03:27
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0008_remove_order_billing_address_and_more'),
|
||||||
|
('accounts', '0004_transfer_address_data_to_user_model'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='addresses',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='default_billing_address',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='default_shipping_address',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Address',
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -5,76 +5,29 @@ from django.contrib.auth.models import AbstractUser
|
|||||||
from localflavor.us.us_states import USPS_CHOICES
|
from localflavor.us.us_states import USPS_CHOICES
|
||||||
|
|
||||||
|
|
||||||
class Address(models.Model):
|
class User(AbstractUser):
|
||||||
first_name = models.CharField(max_length=256, blank=True)
|
stripe_id = models.CharField(max_length=255, blank=True)
|
||||||
last_name = models.CharField(max_length=256, blank=True)
|
|
||||||
street_address_1 = models.CharField(max_length=256, blank=True)
|
# Shipping address
|
||||||
street_address_2 = models.CharField(max_length=256, blank=True)
|
shipping_street_address_1 = models.CharField(max_length=256, blank=True)
|
||||||
city = models.CharField(max_length=256, blank=True)
|
shipping_street_address_2 = models.CharField(max_length=256, blank=True)
|
||||||
state = models.CharField(
|
shipping_city = models.CharField(max_length=256, blank=True)
|
||||||
|
shipping_state = models.CharField(
|
||||||
max_length=2,
|
max_length=2,
|
||||||
choices=USPS_CHOICES,
|
choices=USPS_CHOICES,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
postal_code = models.CharField(max_length=20, blank=True)
|
shipping_postal_code = models.CharField(max_length=20, blank=True)
|
||||||
|
|
||||||
def as_stripe_dict(self):
|
@property
|
||||||
return {
|
def has_shipping_address(self):
|
||||||
'name': f'{self.first_name} {self.last_name}',
|
if (self.shipping_street_address_1 != ''
|
||||||
'address': {
|
and self.shipping_street_address_2 != ''
|
||||||
'line1': self.street_address_1,
|
and self.shipping_city != ''
|
||||||
'line2': self.street_address_2,
|
and self.shipping_state != ''
|
||||||
'city': self.city,
|
and self.shipping_postal_code != ''):
|
||||||
'state': self.state,
|
return True
|
||||||
'postal_code': self.postal_code
|
return False
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"""
|
|
||||||
{self.first_name} {self.last_name}
|
|
||||||
{self.street_address_1}
|
|
||||||
{self.street_address_2}
|
|
||||||
{self.city}, {self.state}, {self.postal_code}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
yield ('address_line_1', self.street_address_1),
|
|
||||||
yield ('address_line_2', self.street_address_2),
|
|
||||||
yield ('admin_area_2', self.city),
|
|
||||||
yield ('admin_area_1', self.state),
|
|
||||||
yield ('postal_code', self.postal_code),
|
|
||||||
yield ('country_code', 'US')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
constraints = [
|
|
||||||
models.UniqueConstraint(
|
|
||||||
name='accounts_address_all_key',
|
|
||||||
fields=[
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'street_address_1',
|
|
||||||
'street_address_2',
|
|
||||||
'city',
|
|
||||||
'state',
|
|
||||||
'postal_code'
|
|
||||||
],
|
|
||||||
violation_error_message='Duplicate: Address already exists.'
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
|
||||||
addresses = models.ManyToManyField(
|
|
||||||
Address, blank=True, related_name="user_addresses"
|
|
||||||
)
|
|
||||||
default_shipping_address = models.ForeignKey(
|
|
||||||
Address, related_name="+", null=True, blank=True, on_delete=models.SET_NULL
|
|
||||||
)
|
|
||||||
default_billing_address = models.ForeignKey(
|
|
||||||
Address, related_name="+", null=True, blank=True, on_delete=models.SET_NULL
|
|
||||||
)
|
|
||||||
stripe_id = models.CharField(max_length=255, blank=True)
|
|
||||||
|
|
||||||
def get_or_create_stripe_id(self):
|
def get_or_create_stripe_id(self):
|
||||||
if not self.stripe_id:
|
if not self.stripe_id:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from django.dispatch import receiver
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .models import Address, User
|
from .models import User
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
stripe.api_key = settings.STRIPE_API_KEY
|
stripe.api_key = settings.STRIPE_API_KEY
|
||||||
@ -16,3 +16,4 @@ def user_saved(sender, instance, created, **kwargs):
|
|||||||
logger.info('User was saved')
|
logger.info('User was saved')
|
||||||
if created or not instance.stripe_id:
|
if created or not instance.stripe_id:
|
||||||
instance.get_or_create_stripe_id()
|
instance.get_or_create_stripe_id()
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +1,9 @@
|
|||||||
from allauth.account.models import EmailAddress
|
from .models import User
|
||||||
|
|
||||||
from .models import Address, User
|
|
||||||
from .tasks import send_account_created_email
|
|
||||||
|
|
||||||
|
|
||||||
def get_or_create_customer(request, shipping_address):
|
def get_or_create_customer(request, shipping_address):
|
||||||
address, a_created = Address.objects.get_or_create(
|
|
||||||
first_name=shipping_address['first_name'],
|
|
||||||
last_name=shipping_address['last_name'],
|
|
||||||
street_address_1=shipping_address['street_address_1'],
|
|
||||||
street_address_2=shipping_address['street_address_2'],
|
|
||||||
city=shipping_address['city'],
|
|
||||||
state=shipping_address['state'],
|
|
||||||
postal_code=shipping_address['postal_code']
|
|
||||||
)
|
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
user = request.user
|
user = request.user
|
||||||
user.addresses.add(address)
|
|
||||||
if not user.default_shipping_address:
|
|
||||||
user.default_shipping_address = address
|
|
||||||
user.save()
|
|
||||||
else:
|
else:
|
||||||
user, u_created = User.objects.get_or_create(
|
user, u_created = User.objects.get_or_create(
|
||||||
email=shipping_address['email'].lower(),
|
email=shipping_address['email'].lower(),
|
||||||
@ -29,27 +12,17 @@ def get_or_create_customer(request, shipping_address):
|
|||||||
'is_staff': False,
|
'is_staff': False,
|
||||||
'is_active': True,
|
'is_active': True,
|
||||||
'is_superuser': False,
|
'is_superuser': False,
|
||||||
'first_name': address.first_name,
|
'first_name': shipping_address['first_name'],
|
||||||
'last_name': address.last_name,
|
'last_name': shipping_address['last_name'],
|
||||||
'default_shipping_address': address,
|
'shipping_street_address_1': shipping_address['street_address_1'],
|
||||||
|
'shipping_street_address_2': shipping_address['street_address_2'],
|
||||||
|
'shipping_city': shipping_address['city'],
|
||||||
|
'shipping_state': shipping_address['state'],
|
||||||
|
'shipping_postal_code': shipping_address['postal_code']
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if u_created:
|
if u_created:
|
||||||
password = User.objects.make_random_password()
|
user.make_random_password()
|
||||||
user.set_password(password)
|
|
||||||
user.addresses.add(address)
|
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
EmailAddress.objects.create(
|
return user
|
||||||
user=user, email=user.email, primary=True, verified=False
|
|
||||||
)
|
|
||||||
|
|
||||||
u = {
|
|
||||||
'full_name': user.get_full_name(),
|
|
||||||
'email': user.email,
|
|
||||||
'password': password
|
|
||||||
}
|
|
||||||
|
|
||||||
send_account_created_email.delay(u)
|
|
||||||
|
|
||||||
return user, address
|
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 02:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0003_rename_max_order_per_customer_productvariant_order_limit'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_city',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_postal_code',
|
||||||
|
field=models.CharField(blank=True, max_length=20),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_state',
|
||||||
|
field=models.CharField(blank=True, choices=[('AL', 'Alabama'), ('AK', 'Alaska'), ('AS', 'American Samoa'), ('AZ', 'Arizona'), ('AR', 'Arkansas'), ('AA', 'Armed Forces Americas'), ('AE', 'Armed Forces Europe'), ('AP', 'Armed Forces Pacific'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DE', 'Delaware'), ('DC', 'District of Columbia'), ('FM', 'Federated States of Micronesia'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('IA', 'Iowa'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('ME', 'Maine'), ('MH', 'Marshall Islands'), ('MD', 'Maryland'), ('MA', 'Massachusetts'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MS', 'Mississippi'), ('MO', 'Missouri'), ('MT', 'Montana'), ('NE', 'Nebraska'), ('NV', 'Nevada'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NY', 'New York'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('MP', 'Northern Mariana Islands'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PW', 'Palau'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VT', 'Vermont'), ('VI', 'Virgin Islands'), ('VA', 'Virginia'), ('WA', 'Washington'), ('WV', 'West Virginia'), ('WI', 'Wisconsin'), ('WY', 'Wyoming')], max_length=2),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_street_address_1',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_street_address_2',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_city',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_postal_code',
|
||||||
|
field=models.CharField(blank=True, max_length=20),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_state',
|
||||||
|
field=models.CharField(blank=True, choices=[('AL', 'Alabama'), ('AK', 'Alaska'), ('AS', 'American Samoa'), ('AZ', 'Arizona'), ('AR', 'Arkansas'), ('AA', 'Armed Forces Americas'), ('AE', 'Armed Forces Europe'), ('AP', 'Armed Forces Pacific'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DE', 'Delaware'), ('DC', 'District of Columbia'), ('FM', 'Federated States of Micronesia'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('IA', 'Iowa'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('ME', 'Maine'), ('MH', 'Marshall Islands'), ('MD', 'Maryland'), ('MA', 'Massachusetts'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MS', 'Mississippi'), ('MO', 'Missouri'), ('MT', 'Montana'), ('NE', 'Nebraska'), ('NV', 'Nevada'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NY', 'New York'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('MP', 'Northern Mariana Islands'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PW', 'Palau'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VT', 'Vermont'), ('VI', 'Virgin Islands'), ('VA', 'Virginia'), ('WA', 'Washington'), ('WV', 'West Virginia'), ('WI', 'Wisconsin'), ('WY', 'Wyoming')], max_length=2),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_street_address_1',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_street_address_2',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 02:59
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def copy_address_to_order(apps, schema_editor):
|
||||||
|
Order = apps.get_model("core", "Order")
|
||||||
|
|
||||||
|
for order in Order.objects.all():
|
||||||
|
if order.shipping_address:
|
||||||
|
order.shipping_street_address_1 = order.shipping_address.street_address_1
|
||||||
|
order.shipping_street_address_2 = order.shipping_address.street_address_2
|
||||||
|
order.shipping_city = order.shipping_address.city
|
||||||
|
order.shipping_state = order.shipping_address.state
|
||||||
|
order.shipping_postal_code = order.shipping_address.postal_code
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
|
||||||
|
def copy_address_to_subscription(apps, schema_editor):
|
||||||
|
Subscription = apps.get_model("core", "Subscription")
|
||||||
|
|
||||||
|
for subscription in Subscription.objects.all():
|
||||||
|
if subscription.shipping_address:
|
||||||
|
subscription.shipping_street_address_1 = subscription.shipping_address.street_address_1
|
||||||
|
subscription.shipping_street_address_2 = subscription.shipping_address.street_address_2
|
||||||
|
subscription.shipping_city = subscription.shipping_address.city
|
||||||
|
subscription.shipping_state = subscription.shipping_address.state
|
||||||
|
subscription.shipping_postal_code = subscription.shipping_address.postal_code
|
||||||
|
subscription.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0004_order_shipping_city_order_shipping_postal_code_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(copy_address_to_order),
|
||||||
|
migrations.RunPython(copy_address_to_subscription)
|
||||||
|
]
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 03:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0005_transfer_address_data_to_order_and_subscription_models'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_first_name',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_last_name',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_first_name',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_last_name',
|
||||||
|
field=models.CharField(blank=True, max_length=256),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 03:20
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def copy_address_to_order(apps, schema_editor):
|
||||||
|
Order = apps.get_model("core", "Order")
|
||||||
|
|
||||||
|
for order in Order.objects.all():
|
||||||
|
if order.shipping_address:
|
||||||
|
order.shipping_first_name = order.shipping_address.first_name
|
||||||
|
order.shipping_last_name = order.shipping_address.last_name
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
|
||||||
|
def copy_address_to_subscription(apps, schema_editor):
|
||||||
|
Subscription = apps.get_model("core", "Subscription")
|
||||||
|
|
||||||
|
for subscription in Subscription.objects.all():
|
||||||
|
if subscription.shipping_address:
|
||||||
|
subscription.shipping_first_name = subscription.shipping_address.first_name
|
||||||
|
subscription.shipping_last_name = subscription.shipping_address.last_name
|
||||||
|
subscription.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0006_order_shipping_first_name_order_shipping_last_name_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(copy_address_to_order),
|
||||||
|
migrations.RunPython(copy_address_to_subscription)
|
||||||
|
]
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-07-15 03:27
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0007_transfer_address_first_and_last_names_to_order_and_subscriptions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='order',
|
||||||
|
name='billing_address',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='order',
|
||||||
|
name='shipping_address',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='subscription',
|
||||||
|
name='shipping_address',
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -16,8 +16,9 @@ from django.contrib.postgres.fields import ArrayField, HStoreField
|
|||||||
from django.forms.models import model_to_dict
|
from django.forms.models import model_to_dict
|
||||||
|
|
||||||
from django_measurement.models import MeasurementField
|
from django_measurement.models import MeasurementField
|
||||||
|
from localflavor.us.us_states import USPS_CHOICES
|
||||||
|
|
||||||
from accounts.models import User, Address
|
from accounts.models import User
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
DiscountValueType,
|
DiscountValueType,
|
||||||
@ -337,20 +338,18 @@ class Order(models.Model):
|
|||||||
default=OrderStatus.UNFULFILLED,
|
default=OrderStatus.UNFULFILLED,
|
||||||
choices=OrderStatus.CHOICES
|
choices=OrderStatus.CHOICES
|
||||||
)
|
)
|
||||||
billing_address = models.ForeignKey(
|
# Shipping address
|
||||||
Address,
|
shipping_first_name = models.CharField(max_length=256, blank=True)
|
||||||
related_name="+",
|
shipping_last_name = models.CharField(max_length=256, blank=True)
|
||||||
editable=False,
|
shipping_street_address_1 = models.CharField(max_length=256, blank=True)
|
||||||
null=True,
|
shipping_street_address_2 = models.CharField(max_length=256, blank=True)
|
||||||
on_delete=models.SET_NULL
|
shipping_city = models.CharField(max_length=256, blank=True)
|
||||||
)
|
shipping_state = models.CharField(
|
||||||
shipping_address = models.ForeignKey(
|
max_length=2,
|
||||||
Address,
|
choices=USPS_CHOICES,
|
||||||
related_name="+",
|
blank=True
|
||||||
editable=False,
|
|
||||||
null=True,
|
|
||||||
on_delete=models.SET_NULL
|
|
||||||
)
|
)
|
||||||
|
shipping_postal_code = models.CharField(max_length=20, blank=True)
|
||||||
coupon = models.ForeignKey(
|
coupon = models.ForeignKey(
|
||||||
Coupon,
|
Coupon,
|
||||||
related_name='orders',
|
related_name='orders',
|
||||||
@ -544,13 +543,18 @@ class Subscription(models.Model):
|
|||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
shipping_address = models.ForeignKey(
|
# Shipping address
|
||||||
Address,
|
shipping_first_name = models.CharField(max_length=256, blank=True)
|
||||||
related_name='+',
|
shipping_last_name = models.CharField(max_length=256, blank=True)
|
||||||
editable=False,
|
shipping_street_address_1 = models.CharField(max_length=256, blank=True)
|
||||||
null=True,
|
shipping_street_address_2 = models.CharField(max_length=256, blank=True)
|
||||||
on_delete=models.SET_NULL
|
shipping_city = models.CharField(max_length=256, blank=True)
|
||||||
|
shipping_state = models.CharField(
|
||||||
|
max_length=2,
|
||||||
|
choices=USPS_CHOICES,
|
||||||
|
blank=True
|
||||||
)
|
)
|
||||||
|
shipping_postal_code = models.CharField(max_length=20, blank=True)
|
||||||
items = ArrayField(
|
items = ArrayField(
|
||||||
models.JSONField(blank=True, null=True),
|
models.JSONField(blank=True, null=True),
|
||||||
default=list
|
default=list
|
||||||
|
|||||||
@ -53,13 +53,13 @@ def transaction_created(sender, instance, created, **kwargs):
|
|||||||
'shipping_total': str(instance.order.shipping_total),
|
'shipping_total': str(instance.order.shipping_total),
|
||||||
'total_amount': str(instance.order.total_amount),
|
'total_amount': str(instance.order.total_amount),
|
||||||
'shipping_address': {
|
'shipping_address': {
|
||||||
'first_name': instance.order.shipping_address.first_name,
|
'first_name': instance.order.shipping_first_name,
|
||||||
'last_name': instance.order.shipping_address.last_name,
|
'last_name': instance.order.shipping_last_name,
|
||||||
'street_address_1': instance.order.shipping_address.street_address_1,
|
'street_address_1': instance.order.shipping_street_address_1,
|
||||||
'street_address_2': instance.order.shipping_address.street_address_2,
|
'street_address_2': instance.order.shipping_street_address_2,
|
||||||
'city': instance.order.shipping_address.city,
|
'city': instance.order.shipping_city,
|
||||||
'state': instance.order.shipping_address.state,
|
'state': instance.order.shipping_state,
|
||||||
'postal_code': instance.order.shipping_address.postal_code
|
'postal_code': instance.order.shipping_postal_code
|
||||||
},
|
},
|
||||||
'line_items': list(
|
'line_items': list(
|
||||||
format_order_lines(instance.order.lines.all())
|
format_order_lines(instance.order.lines.all())
|
||||||
|
|||||||
@ -19,21 +19,14 @@
|
|||||||
<h4>Details</h4>
|
<h4>Details</h4>
|
||||||
</header>
|
</header>
|
||||||
<dl class="panel-datalist">
|
<dl class="panel-datalist">
|
||||||
<dt>Primary email address</dt>
|
<dt>Email address</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<a href="mailto:{{ customer.email }}">{{ customer.email }} ↗</a>
|
<a href="mailto:{{ customer.email }}">{{ customer.email }} ↗</a>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Default shipping address</dt>
|
<dt>Shipping address</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% include 'dashboard/partials/_address.html' with address=customer.default_shipping_address %}
|
{% include 'dashboard/partials/_address.html' with full_name=customer.get_full_name address=customer %}
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>All addresses</dt>
|
|
||||||
<dd>
|
|
||||||
{% for address in customer.addresses.all %}
|
|
||||||
{% include 'dashboard/partials/_address.html' with address=address %}
|
|
||||||
{% endfor %}
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -133,7 +133,7 @@
|
|||||||
<div class="panel-section panel-shipping">
|
<div class="panel-section panel-shipping">
|
||||||
<div>
|
<div>
|
||||||
<strong>Shipping address</strong>
|
<strong>Shipping address</strong>
|
||||||
{% include 'dashboard/partials/_address.html' with address=order.shipping_address %}
|
{% include 'dashboard/partials/_address.html' with full_name=order.customer.get_full_name address=order %}
|
||||||
</div>
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
</header>
|
</header>
|
||||||
<div class="panel-section">
|
<div class="panel-section">
|
||||||
<strong>Shipping address</strong>
|
<strong>Shipping address</strong>
|
||||||
{% include 'dashboard/partials/_address.html' with address=order.shipping_address %}
|
{% include 'dashboard/partials/_address.html' with full_name=order.customer.get_full_name address=order %}
|
||||||
</div>
|
</div>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
<address>
|
<address>
|
||||||
{{address.first_name}}
|
{{ full_name }}<br>
|
||||||
{{address.last_name}}<br>
|
{{ address.shipping_street_address_1 }}<br>
|
||||||
{{address.street_address_1}}<br>
|
{% if address.shipping_street_address_2 %}
|
||||||
{% if address.street_address_2 %}
|
{{ address.shipping_street_address_2 }}<br>
|
||||||
{{address.street_address_2}}<br>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{address.city}}, {{address.state}}, {{address.postal_code}}
|
{{ address.shipping_city }}, {{ address.shipping_state }}, {{ address.shipping_postal_code }}
|
||||||
</address>
|
</address>
|
||||||
|
|||||||
@ -31,7 +31,6 @@ from django.db.models.functions import Coalesce
|
|||||||
|
|
||||||
from accounts.models import User
|
from accounts.models import User
|
||||||
from accounts.utils import get_or_create_customer
|
from accounts.utils import get_or_create_customer
|
||||||
from accounts.forms import AddressForm
|
|
||||||
from core.models import (
|
from core.models import (
|
||||||
ProductCategory,
|
ProductCategory,
|
||||||
Product,
|
Product,
|
||||||
@ -259,8 +258,6 @@ class OrderDetailView(LoginRequiredMixin, DetailView):
|
|||||||
self.kwargs.get(self.pk_url_kwarg)
|
self.kwargs.get(self.pk_url_kwarg)
|
||||||
).select_related(
|
).select_related(
|
||||||
'customer',
|
'customer',
|
||||||
'billing_address',
|
|
||||||
'shipping_address'
|
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
'lines__variant__product__productphoto_set'
|
'lines__variant__product__productphoto_set'
|
||||||
)
|
)
|
||||||
@ -717,9 +714,11 @@ class CustomerUpdateView(
|
|||||||
'first_name',
|
'first_name',
|
||||||
'last_name',
|
'last_name',
|
||||||
'email',
|
'email',
|
||||||
'is_staff',
|
'shipping_street_address_1',
|
||||||
'addresses',
|
'shipping_street_address_2',
|
||||||
'default_shipping_address'
|
'shipping_city',
|
||||||
|
'shipping_state',
|
||||||
|
'shipping_postal_code',
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
|
|||||||
@ -25,7 +25,7 @@ services:
|
|||||||
- redis
|
- redis
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
command: sh -c "python manage.py migrate && python manage.py collectstatic --no-input && gunicorn --bind :8000 --reload ptcoffee.wsgi:application"
|
command: gunicorn --bind :8000 --reload ptcoffee.wsgi:application
|
||||||
volumes:
|
volumes:
|
||||||
- .:/app
|
- .:/app
|
||||||
- ./static/:/var/www/static
|
- ./static/:/var/www/static
|
||||||
|
|||||||
@ -19,6 +19,10 @@ server {
|
|||||||
listen [::]:443 ssl http2;
|
listen [::]:443 ssl http2;
|
||||||
server_name ptcoffee.com www.ptcoffee.com;
|
server_name ptcoffee.com www.ptcoffee.com;
|
||||||
|
|
||||||
|
if ($http_host !~* ^(ptcoffee.com|www.ptcoffee.com)$ ) {
|
||||||
|
return 444;
|
||||||
|
}
|
||||||
|
|
||||||
# SSL
|
# SSL
|
||||||
ssl_certificate /etc/letsencrypt/live/ptcoffee.com/fullchain.pem;
|
ssl_certificate /etc/letsencrypt/live/ptcoffee.com/fullchain.pem;
|
||||||
ssl_certificate_key /etc/letsencrypt/live/ptcoffee.com/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/ptcoffee.com/privkey.pem;
|
||||||
|
|||||||
2109
poetry.lock
generated
2109
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -72,10 +72,7 @@ INSTALLED_APPS = [
|
|||||||
|
|
||||||
# 3rd Party
|
# 3rd Party
|
||||||
'django_filters',
|
'django_filters',
|
||||||
'storages',
|
|
||||||
'localflavor',
|
'localflavor',
|
||||||
'django_celery_beat',
|
|
||||||
'django_celery_results',
|
|
||||||
'anymail',
|
'anymail',
|
||||||
'compressor',
|
'compressor',
|
||||||
'allauth',
|
'allauth',
|
||||||
|
|||||||
@ -11,12 +11,9 @@ django = "^4.1.5"
|
|||||||
celery = {extras = ["redis"], version = "^5.2.7"}
|
celery = {extras = ["redis"], version = "^5.2.7"}
|
||||||
django-allauth = "^0.52.0"
|
django-allauth = "^0.52.0"
|
||||||
django-anymail = {extras = ["mailgun"], version = "^9.0"}
|
django-anymail = {extras = ["mailgun"], version = "^9.0"}
|
||||||
django-celery-beat = "^2.4.0"
|
|
||||||
django-celery-results = "^2.4.0"
|
|
||||||
django-compressor = "^4.1"
|
django-compressor = "^4.1"
|
||||||
django-filter = "^22.1"
|
django-filter = "^22.1"
|
||||||
django-measurement = "^3.2.4"
|
django-measurement = "^3.2.4"
|
||||||
django-storages = "^1.13.2"
|
|
||||||
django-templated-email = "^3.0.1"
|
django-templated-email = "^3.0.1"
|
||||||
paypal-checkout-serversdk = "^1.0.1"
|
paypal-checkout-serversdk = "^1.0.1"
|
||||||
pillow = "^9.4.0"
|
pillow = "^9.4.0"
|
||||||
|
|||||||
@ -126,6 +126,21 @@ table a {
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-table {
|
||||||
|
width: unset;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.form-table th,
|
||||||
|
.form-table td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.form-table th {
|
||||||
|
padding: 0 1rem 1rem 0;
|
||||||
|
}
|
||||||
|
.form-table td {
|
||||||
|
padding: 0 0 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Forms
|
Forms
|
||||||
|
|||||||
@ -255,7 +255,7 @@ class Cart:
|
|||||||
if container is None:
|
if container is None:
|
||||||
container = self.get_shipping_container()
|
container = self.get_shipping_container()
|
||||||
|
|
||||||
if not self.total_weight > Weight(lb=0):
|
if self.total_weight <= Weight(lb=0):
|
||||||
return Decimal('0.00')
|
return Decimal('0.00')
|
||||||
|
|
||||||
if len(self) > 0 and self.session.get('shipping_address'):
|
if len(self) > 0 and self.session.get('shipping_address'):
|
||||||
@ -286,11 +286,11 @@ class Cart:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if usps_rate_request['service'] == ShippingContainer.PRIORITY:
|
if usps_rate_request['service'] == ShippingContainer.PRIORITY:
|
||||||
shipping_cost = Decimal(postage['Rate'])
|
shipping_price = Decimal(postage['Rate'])
|
||||||
elif usps_rate_request['service'] == ShippingContainer.PRIORITY_COMMERCIAL:
|
elif usps_rate_request['service'] == ShippingContainer.PRIORITY_COMMERCIAL:
|
||||||
shipping_cost = Decimal(postage['CommercialRate'])
|
shipping_price = Decimal(postage['CommercialRate'])
|
||||||
|
|
||||||
return shipping_cost
|
return shipping_price
|
||||||
else:
|
else:
|
||||||
raise ShippingAddressError(
|
raise ShippingAddressError(
|
||||||
'Could not retrieve shipping address.'
|
'Could not retrieve shipping address.'
|
||||||
|
|||||||
@ -5,61 +5,32 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<article>
|
<article>
|
||||||
<header class="article__header--with-action">
|
|
||||||
<h1>{{customer.get_full_name}}</h1>
|
|
||||||
<a href="{% url 'storefront:customer-update' customer.pk %}" class="btn">Edit profile</a>
|
|
||||||
</header>
|
|
||||||
<section>
|
<section>
|
||||||
<h4>Info</h4>
|
<h2>My Account</h2>
|
||||||
|
<p>
|
||||||
|
<a href="{% url 'account_change_password' %}">Change password</a>
|
||||||
|
</p>
|
||||||
<div class="customer__detail-section">
|
<div class="customer__detail-section">
|
||||||
<div>
|
<div>
|
||||||
<strong>Email address</strong><br>
|
<strong>Email address</strong> <a href="{% url 'storefront:customer-update' customer.pk %}">Change</a><br>
|
||||||
{{customer.email}}<br>
|
{{customer.email}}
|
||||||
<a href="{% url 'account_email' %}">Manage</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Default shipping address</strong>
|
<strong>Shipping address</strong> <a href="{% url 'storefront:customer-shipping-address-update' customer.pk %}">Change</a>
|
||||||
{% with shipping_address=customer.default_shipping_address %}
|
<address>
|
||||||
<address>
|
{{ customer.get_full_name }}<br>
|
||||||
{{shipping_address.first_name}}
|
{{customer.shipping_street_address_1}}<br>
|
||||||
{{shipping_address.last_name}}<br>
|
{% if shipping_street_address_2 %}
|
||||||
{{shipping_address.street_address_1}}<br>
|
{{customer.shipping_street_address_2}}<br>
|
||||||
{% if shipping_address.street_address_2 %}
|
{% endif %}
|
||||||
{{shipping_address.street_address_2}}<br>
|
{{customer.shipping_city}}, {{customer.shipping_state}}, {{customer.shipping_postal_code}}
|
||||||
{% endif %}
|
</address>
|
||||||
{{shipping_address.city}}, {{shipping_address.state}}, {{shipping_address.postal_code}}
|
|
||||||
</address>
|
|
||||||
{% endwith %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<h4>Your addresses</h4>
|
|
||||||
<p>
|
|
||||||
<a href="{% url 'storefront:customer-address-create' user.pk %}" class="btn">+ New address</a>
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
{% for address in customer.addresses.all %}
|
|
||||||
<p>
|
|
||||||
<address>
|
|
||||||
{{address.first_name}}
|
|
||||||
{{address.last_name}}<br>
|
|
||||||
{{address.street_address_1}}<br>
|
|
||||||
{% if address.street_address_2 %}
|
|
||||||
{{address.street_address_2}}<br>
|
|
||||||
{% endif %}
|
|
||||||
{{address.city}}, {{address.state}}, {{address.postal_code}}
|
|
||||||
</address>
|
|
||||||
<a href="{% url 'storefront:address-update' customer.pk address.pk %}">Edit</a>
|
|
||||||
</p>
|
|
||||||
{% empty %}
|
|
||||||
<p>No other addresses.</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{% if customer.subscriptions.count > 0 %}
|
{% if customer.subscriptions.count > 0 %}
|
||||||
<section>
|
<section>
|
||||||
<h3>Your subscriptions</h3>
|
<h3>My subscriptions</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -81,7 +52,7 @@
|
|||||||
</section>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<section>
|
<section>
|
||||||
<h3>Your orders</h3>
|
<h3>My orders</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@ -5,17 +5,22 @@
|
|||||||
<header>
|
<header>
|
||||||
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">← Back</a></p>
|
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">← Back</a></p>
|
||||||
<h1>Update your profile</h1>
|
<h1>Update your profile</h1>
|
||||||
<p>
|
|
||||||
<a href="{% url 'account_change_password' %}">Change password</a>
|
|
||||||
</p>
|
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<section>
|
||||||
<form method="POST" action="{% url 'storefront:customer-update' customer.pk %}">
|
<form method="POST" action="{% url 'storefront:customer-update' customer.pk %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{form.as_p}}
|
<table class="form-table">
|
||||||
<p>
|
{{form.as_table}}
|
||||||
<input type="submit" value="Save changes">
|
<tfoot>
|
||||||
</p>
|
<tr>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="submit">Save changes</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">← Back</a></p>
|
||||||
|
<h1>Update your shipping address</h1>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table class="form-table">
|
||||||
|
{{form.as_table}}
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="submit">Save changes</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
{% endblock %}
|
||||||
@ -89,26 +89,16 @@ urlpatterns = [
|
|||||||
views.CustomerUpdateView.as_view(),
|
views.CustomerUpdateView.as_view(),
|
||||||
name='customer-update',
|
name='customer-update',
|
||||||
),
|
),
|
||||||
# path(
|
path(
|
||||||
# 'delete/',
|
'shipping-address/update/',
|
||||||
# views.CustomerDeleteView.as_view(),
|
views.CustomerShippingAddressUpdateView.as_view(),
|
||||||
# name='customer-delete'
|
name='customer-shipping-address-update',
|
||||||
# ),
|
),
|
||||||
path(
|
path(
|
||||||
'orders/<int:order_pk>/',
|
'orders/<int:order_pk>/',
|
||||||
views.OrderDetailView.as_view(),
|
views.OrderDetailView.as_view(),
|
||||||
name='order-detail',
|
name='order-detail',
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
'addresses/new/',
|
|
||||||
views.CustomerAddressCreateView.as_view(),
|
|
||||||
name='customer-address-create',
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'addresses/<int:address_pk>/update/',
|
|
||||||
views.CustomerAddressUpdateView.as_view(),
|
|
||||||
name='address-update',
|
|
||||||
)
|
|
||||||
])),
|
])),
|
||||||
|
|
||||||
path(
|
path(
|
||||||
|
|||||||
@ -34,11 +34,9 @@ from paypalcheckoutsdk.orders import OrdersCreateRequest, OrdersCaptureRequest
|
|||||||
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment
|
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment
|
||||||
from moneyed import Money, USD
|
from moneyed import Money, USD
|
||||||
|
|
||||||
from accounts.models import User, Address
|
from accounts.models import User
|
||||||
from accounts.utils import get_or_create_customer
|
from accounts.utils import get_or_create_customer
|
||||||
from accounts.forms import (
|
from accounts.forms import CustomerUpdateForm, CustomerShippingAddressUpdateForm
|
||||||
AddressForm as AccountAddressForm, CustomerUpdateForm
|
|
||||||
)
|
|
||||||
from core.models import (
|
from core.models import (
|
||||||
ProductCategory, Product, ProductVariant, ProductOption,
|
ProductCategory, Product, ProductVariant, ProductOption,
|
||||||
Order, Transaction, OrderLine, Coupon, ShippingRate,
|
Order, Transaction, OrderLine, Coupon, ShippingRate,
|
||||||
@ -252,16 +250,15 @@ class CheckoutAddressView(FormView):
|
|||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
initial = None
|
initial = None
|
||||||
if user.is_authenticated and user.default_shipping_address:
|
if user.is_authenticated:
|
||||||
address = user.default_shipping_address
|
|
||||||
initial = {
|
initial = {
|
||||||
'full_name': address.first_name + ' ' + address.last_name,
|
'full_name': user.first_name + ' ' + user.last_name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'street_address_1': address.street_address_1,
|
'street_address_1': user.shipping_street_address_1,
|
||||||
'street_address_2': address.street_address_2,
|
'street_address_2': user.shipping_street_address_2,
|
||||||
'city': address.city,
|
'city': user.shipping_city,
|
||||||
'state': address.state,
|
'state': user.shipping_state,
|
||||||
'postal_code': address.postal_code
|
'postal_code': user.shipping_postal_code
|
||||||
}
|
}
|
||||||
elif self.request.session.get('shipping_address'):
|
elif self.request.session.get('shipping_address'):
|
||||||
address = self.request.session.get('shipping_address')
|
address = self.request.session.get('shipping_address')
|
||||||
@ -413,7 +410,14 @@ class OrderCreateView(CreateView):
|
|||||||
shipping_container = cart.get_shipping_container()
|
shipping_container = cart.get_shipping_container()
|
||||||
form.instance.shipping_total = cart.get_shipping_price(shipping_container)
|
form.instance.shipping_total = cart.get_shipping_price(shipping_container)
|
||||||
shipping_address = self.request.session.get('shipping_address')
|
shipping_address = self.request.session.get('shipping_address')
|
||||||
form.instance.customer, form.instance.shipping_address = get_or_create_customer(self.request, shipping_address)
|
form.instance.shipping_first_name = shipping_address['first_name']
|
||||||
|
form.instance.shipping_last_name = shipping_address['last_name']
|
||||||
|
form.instance.shipping_street_address_1 = shipping_address['street_address_1']
|
||||||
|
form.instance.shipping_street_address_2 = shipping_address['street_address_2']
|
||||||
|
form.instance.shipping_city = shipping_address['city']
|
||||||
|
form.instance.shipping_state = shipping_address['state']
|
||||||
|
form.instance.shipping_postal_code = shipping_address['postal_code']
|
||||||
|
form.instance.customer = get_or_create_customer(self.request, shipping_address)
|
||||||
form.instance.status = OrderStatus.DRAFT
|
form.instance.status = OrderStatus.DRAFT
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
bulk_list = cart.build_bulk_list(self.object)
|
bulk_list = cart.build_bulk_list(self.object)
|
||||||
@ -443,7 +447,14 @@ class FreeOrderCreateView(CreateView):
|
|||||||
shipping_container = cart.get_shipping_container()
|
shipping_container = cart.get_shipping_container()
|
||||||
form.instance.shipping_total = cart.get_shipping_price(shipping_container)
|
form.instance.shipping_total = cart.get_shipping_price(shipping_container)
|
||||||
shipping_address = self.request.session.get('shipping_address')
|
shipping_address = self.request.session.get('shipping_address')
|
||||||
form.instance.customer, form.instance.shipping_address = get_or_create_customer(self.request, shipping_address)
|
form.instance.shipping_first_name = shipping_address['first_name']
|
||||||
|
form.instance.shipping_last_name = shipping_address['last_name']
|
||||||
|
form.instance.shipping_street_address_1 = shipping_address['street_address_1']
|
||||||
|
form.instance.shipping_street_address_2 = shipping_address['street_address_2']
|
||||||
|
form.instance.shipping_city = shipping_address['city']
|
||||||
|
form.instance.shipping_state = shipping_address['state']
|
||||||
|
form.instance.shipping_postal_code = shipping_address['postal_code']
|
||||||
|
form.instance.customer = get_or_create_customer(self.request, shipping_address)
|
||||||
form.instance.status = OrderStatus.UNFULFILLED
|
form.instance.status = OrderStatus.UNFULFILLED
|
||||||
self.object = form.save()
|
self.object = form.save()
|
||||||
bulk_list = cart.build_bulk_list(self.object)
|
bulk_list = cart.build_bulk_list(self.object)
|
||||||
@ -546,6 +557,24 @@ class CustomerUpdateView(UserPassesTestMixin, LoginRequiredMixin, UpdateView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomerShippingAddressUpdateView(UserPassesTestMixin, LoginRequiredMixin, UpdateView):
|
||||||
|
model = User
|
||||||
|
template_name = 'storefront/customer_shipping_address_form.html'
|
||||||
|
context_object_name = 'customer'
|
||||||
|
form_class = CustomerShippingAddressUpdateForm
|
||||||
|
permission_denied_message = 'Not authorized.'
|
||||||
|
raise_exception = True
|
||||||
|
|
||||||
|
def test_func(self):
|
||||||
|
return self.request.user.pk == self.get_object().pk
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse(
|
||||||
|
'storefront:customer-detail', kwargs={'pk': self.object.pk}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class OrderDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
|
class OrderDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
|
||||||
model = Order
|
model = Order
|
||||||
template_name = 'storefront/order_detail.html'
|
template_name = 'storefront/order_detail.html'
|
||||||
@ -562,58 +591,6 @@ class OrderDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class CustomerAddressCreateView(
|
|
||||||
UserPassesTestMixin, LoginRequiredMixin, CreateView
|
|
||||||
):
|
|
||||||
model = Address
|
|
||||||
template_name = 'storefront/address_create_form.html'
|
|
||||||
form_class = AccountAddressForm
|
|
||||||
permission_denied_message = 'Not authorized.'
|
|
||||||
raise_exception = True
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return self.request.user.pk == self.kwargs['pk']
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
context['customer'] = User.objects.get(pk=self.kwargs['pk'])
|
|
||||||
return context
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
customer = User.objects.get(pk=self.kwargs['pk'])
|
|
||||||
self.object = form.save()
|
|
||||||
customer.addresses.add(self.object)
|
|
||||||
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return reverse(
|
|
||||||
'storefront:customer-detail', kwargs={'pk': self.kwargs['pk']}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CustomerAddressUpdateView(
|
|
||||||
UserPassesTestMixin, LoginRequiredMixin, UpdateView
|
|
||||||
):
|
|
||||||
model = Address
|
|
||||||
pk_url_kwarg = 'address_pk'
|
|
||||||
template_name = 'storefront/address_form.html'
|
|
||||||
form_class = AccountAddressForm
|
|
||||||
permission_denied_message = 'Not authorized.'
|
|
||||||
raise_exception = True
|
|
||||||
|
|
||||||
def test_func(self):
|
|
||||||
return self.request.user.pk == self.kwargs['pk']
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super().get_context_data(**kwargs)
|
|
||||||
context['customer'] = User.objects.get(pk=self.kwargs['pk'])
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return reverse('storefront:customer-detail', kwargs={'pk': self.kwargs['pk']})
|
|
||||||
|
|
||||||
|
|
||||||
class AboutView(TemplateView):
|
class AboutView(TemplateView):
|
||||||
template_name = 'storefront/about.html'
|
template_name = 'storefront/about.html'
|
||||||
|
|
||||||
@ -754,7 +731,7 @@ class SubscriptionCreateView(SuccessMessageMixin, CreateView):
|
|||||||
).get('recurring')
|
).get('recurring')
|
||||||
shipping_cost = get_shipping_cost(
|
shipping_cost = get_shipping_cost(
|
||||||
self.object.total_weight,
|
self.object.total_weight,
|
||||||
self.object.shipping_address.postal_code
|
self.object.shipping_postal_code
|
||||||
) * 100
|
) * 100
|
||||||
line_items.append({
|
line_items.append({
|
||||||
'price_data': {
|
'price_data': {
|
||||||
@ -789,7 +766,16 @@ class SubscriptionCreateView(SuccessMessageMixin, CreateView):
|
|||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
shipping_address = self.request.session.get('shipping_address')
|
shipping_address = self.request.session.get('shipping_address')
|
||||||
subscription = self.request.session.get('subscription')
|
subscription = self.request.session.get('subscription')
|
||||||
form.instance.customer, form.instance.shipping_address = get_or_create_customer(self.request, shipping_address)
|
form.instance.shipping_first_name = shipping_address['first_name']
|
||||||
|
form.instance.shipping_last_name = shipping_address['last_name']
|
||||||
|
form.instance.shipping_street_address_1 = shipping_address['street_address_1']
|
||||||
|
form.instance.shipping_street_address_2 = shipping_address['street_address_2']
|
||||||
|
form.instance.shipping_city = shipping_address['city']
|
||||||
|
form.instance.shipping_state = shipping_address['state']
|
||||||
|
form.instance.shipping_postal_code = shipping_address['postal_code']
|
||||||
|
form.instance.customer = get_or_create_customer(
|
||||||
|
self.request, shipping_address
|
||||||
|
)
|
||||||
weight, unit = subscription['metadata']['total_weight'].split(':')
|
weight, unit = subscription['metadata']['total_weight'].split(':')
|
||||||
form.instance.total_weight = guess(
|
form.instance.total_weight = guess(
|
||||||
float(weight), unit, measures=[Weight]
|
float(weight), unit, measures=[Weight]
|
||||||
@ -855,3 +841,4 @@ def stripe_webhook(request):
|
|||||||
subscription.create_order(event.data.object)
|
subscription.create_order(event.data.object)
|
||||||
|
|
||||||
return JsonResponse({'status': 'success'})
|
return JsonResponse({'status': 'success'})
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,20 @@
|
|||||||
|
|
||||||
<form method="POST" action="{% url 'account_change_password' %}" class="password_change">
|
<form method="POST" action="{% url 'account_change_password' %}" class="password_change">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
<table class="form-table">
|
||||||
<input type="submit" value="{% trans "Save changes" %}">
|
<tbody>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="submit">Save changes</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</article>
|
</article>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user