parent
e3e6603d65
commit
cd71834fdf
@ -0,0 +1,41 @@ |
|||||||
|
# Generated by Django 5.1 on 2025-05-06 10:21 |
||||||
|
|
||||||
|
import django.db.models.deletion |
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('shop', '0026_alter_order_user'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='ShippingAddress', |
||||||
|
fields=[ |
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('street_address', models.CharField(max_length=255)), |
||||||
|
('apartment', models.CharField(blank=True, max_length=50, null=True)), |
||||||
|
('city', models.CharField(max_length=100)), |
||||||
|
('state', models.CharField(blank=True, max_length=100, null=True)), |
||||||
|
('postal_code', models.CharField(max_length=20)), |
||||||
|
('country', models.CharField(max_length=100)), |
||||||
|
], |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='order', |
||||||
|
name='payment_status', |
||||||
|
field=models.CharField(choices=[('UNPAID', 'Unpaid'), ('PAID', 'Paid'), ('FAILED', 'Failed'), ('REFUNDED', 'Refunded')], default='UNPAID', max_length=20), |
||||||
|
), |
||||||
|
migrations.AlterField( |
||||||
|
model_name='order', |
||||||
|
name='status', |
||||||
|
field=models.CharField(choices=[('PENDING', 'Pending'), ('PAID', 'Paid'), ('SHIPPED', 'Shipped'), ('DELIVERED', 'Delivered'), ('CANCELED', 'Canceled'), ('REFUNDED', 'Refunded'), ('PREPARED', 'Prepared')], default='PENDING', max_length=20), |
||||||
|
), |
||||||
|
migrations.AddField( |
||||||
|
model_name='order', |
||||||
|
name='shipping_address', |
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shop.shippingaddress'), |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
{% extends 'tournaments/base.html' %} |
||||||
|
|
||||||
|
{% block head_title %}Mes Commandes{% endblock %} |
||||||
|
{% block first_title %}Padel Club{% endblock %} |
||||||
|
{% block second_title %}Mes Commandes{% endblock %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
{% include 'shop/partials/navigation_base.html' %} |
||||||
|
|
||||||
|
<div class="grid-x"> |
||||||
|
<div class="cell medium-12 large-6 padding10"> |
||||||
|
<h1 class="club padding10">Mes Commandes</h1> |
||||||
|
<div class="bubble"> |
||||||
|
{% if orders %} |
||||||
|
<table class="order-table"> |
||||||
|
<tbody> |
||||||
|
{% for order in orders %} |
||||||
|
<tr class="{% cycle 'odd-row' 'even-row' %}"> |
||||||
|
<td class="text-left">Commande #{{ order.id }}</td> |
||||||
|
<td> |
||||||
|
<a href="{% url 'shop:order_detail' order.id %}" class="view-btn">Détails</a> |
||||||
|
</td> |
||||||
|
<td class="text-left">{{ order.date_ordered|date:"d/m/Y H:i" }}</td> |
||||||
|
<td class="text-left"> |
||||||
|
{% if order.status == 'PENDING' %} |
||||||
|
<span class="status-badge pending">En attente</span> |
||||||
|
{% elif order.status == 'PAID' %} |
||||||
|
<span class="status-badge paid">Payée</span> |
||||||
|
{% elif order.status == 'PREPARED' %} |
||||||
|
<span class="status-badge prepared">En cours de préparation</span> |
||||||
|
{% elif order.status == 'SHIPPED' %} |
||||||
|
<span class="status-badge shipped">Expédiée</span> |
||||||
|
{% elif order.status == 'DELIVERED' %} |
||||||
|
<span class="status-badge delivered">Livrée</span> |
||||||
|
{% elif order.status == 'CANCELED' %} |
||||||
|
<span class="status-badge canceled">Annulée</span> |
||||||
|
{% elif order.status == 'REFUNDED' %} |
||||||
|
<span class="status-badge refunded">Remboursée</span> |
||||||
|
{% endif %} |
||||||
|
</td> |
||||||
|
<td class="price-column"> |
||||||
|
{% if order.discount_amount > 0 %} |
||||||
|
<span class="original-price">{{ order.total_price }}€</span> |
||||||
|
<span class="discounted-price">{{ order.get_total_after_discount }}€</span> |
||||||
|
{% else %} |
||||||
|
{{ order.total_price }}€ |
||||||
|
{% endif %} |
||||||
|
</td> |
||||||
|
<td class="actions"> |
||||||
|
{% if order.status == 'PENDING' or order.status == 'PAID' %} |
||||||
|
<form method="post" action="{% url 'shop:cancel_order' order.id %}" class="inline-form" onsubmit="return confirm('Êtes-vous sûr de vouloir annuler cette commande?');"> |
||||||
|
{% csrf_token %} |
||||||
|
<button type="submit" class="remove-btn">Annuler</button> |
||||||
|
</form> |
||||||
|
{% endif %} |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{% endfor %} |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
{% else %} |
||||||
|
<div class="empty-orders"> |
||||||
|
<p>Vous n'avez pas encore de commandes.</p> |
||||||
|
<a href="{% url 'shop:product_list' %}" class="confirm-nav-button">Découvrir la boutique</a> |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
|
||||||
|
{% if messages %} |
||||||
|
<div class="messages"> |
||||||
|
{% for message in messages %} |
||||||
|
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}"> |
||||||
|
{{ message }} |
||||||
|
</div> |
||||||
|
{% endfor %} |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% endblock %} |
||||||
@ -0,0 +1,150 @@ |
|||||||
|
{% extends 'tournaments/base.html' %} |
||||||
|
|
||||||
|
{% block head_title %}Détail de commande{% endblock %} |
||||||
|
{% block first_title %}Padel Club{% endblock %} |
||||||
|
{% block second_title %}Détail de commande{% endblock %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
{% include 'shop/partials/navigation_base.html' %} |
||||||
|
|
||||||
|
<div class="grid-x"> |
||||||
|
<div class="cell medium-8 large-8 padding10"> |
||||||
|
<h1 class="club padding10">Commande #{{ order.id }}</h1> |
||||||
|
<div class="bubble"> |
||||||
|
<div class="order-meta"> |
||||||
|
<div class="order-date"> |
||||||
|
<strong>Date:</strong> {{ order.date_ordered|date:"d/m/Y H:i" }} |
||||||
|
</div> |
||||||
|
<div class="order-status"> |
||||||
|
<strong>Statut:</strong> |
||||||
|
{% if order.status == 'PENDING' %} |
||||||
|
<span class="status-badge pending">En attente</span> |
||||||
|
{% elif order.status == 'PREPARED' %} |
||||||
|
<span class="status-badge prepared">En cours de préparation</span> |
||||||
|
{% elif order.status == 'PAID' %} |
||||||
|
<span class="status-badge paid">Payée</span> |
||||||
|
{% elif order.status == 'SHIPPED' %} |
||||||
|
<span class="status-badge shipped">Expédiée</span> |
||||||
|
{% elif order.status == 'DELIVERED' %} |
||||||
|
<span class="status-badge delivered">Livrée</span> |
||||||
|
{% elif order.status == 'CANCELED' %} |
||||||
|
<span class="status-badge canceled">Annulée</span> |
||||||
|
{% elif order.status == 'REFUNDED' %} |
||||||
|
<span class="status-badge refunded">Remboursée</span> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="order-items-section"> |
||||||
|
<h3>Produits</h3> |
||||||
|
{% with items=order_items total_quantity=total_quantity total_price=order.total_price %} |
||||||
|
{% include 'shop/partials/order_items_display.html' with items=items total_quantity=total_quantity total_price=total_price edit_mode=False cancel_mode=order.is_cancellable %} |
||||||
|
{% endwith %} |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="coupon-section"> |
||||||
|
<div>Adresse de livraison (dans la mesure du possible)</div> |
||||||
|
{% if order.shipping_address %} |
||||||
|
<div class="address-details" style="margin: 10px 0; padding: 10px; background: #f8f9fa; border-radius: 4px;"> |
||||||
|
<p style="margin: 0;">{{ order.shipping_address.street_address }}</p> |
||||||
|
{% if order.shipping_address.apartment %} |
||||||
|
<p style="margin: 5px 0;">{{ order.shipping_address.apartment }}</p> |
||||||
|
{% endif %} |
||||||
|
<p style="margin: 0;">{{ order.shipping_address.postal_code }} {{ order.shipping_address.city }}, {{ order.shipping_address.country }}</p> |
||||||
|
</div> |
||||||
|
{% if order.shipping_address_can_be_edited %} |
||||||
|
<button class="edit-address-btn confirm-nav-button" style="margin-top: 10px;" onclick="toggleAddressForm()">Modifier l'adresse</button> |
||||||
|
|
||||||
|
<div id="address-form-container" style="display: none; margin-top: 10px;"> |
||||||
|
<form method="post" action="{% url 'shop:update_shipping_address' order.id %}" class="coupon-form"> |
||||||
|
{% csrf_token %} |
||||||
|
<input type="text" name="street_address" class="address-input" style="width: 100%;" placeholder="Adresse" value="{{ order.shipping_address.street_address }}"> |
||||||
|
<div style="margin: 10px 0;"> |
||||||
|
<input type="text" name="apartment" class="address-input" style="width: 100%;" placeholder="Appartement (optionnel)" value="{{ order.shipping_address.apartment|default:'' }}"> |
||||||
|
</div> |
||||||
|
<div style="display: flex; gap: 10px;"> |
||||||
|
<input type="text" name="postal_code" class="address-input" style="width: 25%;" placeholder="Code postal" value="{{ order.shipping_address.postal_code }}"> |
||||||
|
<input type="text" name="city" class="address-input" style="width: 25%;" placeholder="Ville" value="{{ order.shipping_address.city }}"> |
||||||
|
<input type="text" name="country" class="address-input" style="width: 25%;" placeholder="Pays" value="{{ order.shipping_address.country }}"> |
||||||
|
</div> |
||||||
|
<button type="submit" class="save-btn confirm-nav-button">Enregistrer</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
{% else %} |
||||||
|
<p>Aucune adresse de livraison renseignée</p> |
||||||
|
{% if order.shipping_address_can_be_edited %} |
||||||
|
<button class="add-address-btn confirm-nav-button" onclick="toggleAddressForm()">Ajouter une adresse</button> |
||||||
|
<div id="address-form-container" style="display: none; margin-top: 10px;"> |
||||||
|
<form method="post" action="{% url 'shop:update_shipping_address' order.id %}" class="coupon-form"> |
||||||
|
{% csrf_token %} |
||||||
|
<input type="text" name="street_address" class="address-input" style="width: 100%;" placeholder="Adresse"> |
||||||
|
<div style="margin: 10px 0;"> |
||||||
|
<input type="text" name="apartment" class="address-input" style="width: 100%;" placeholder="Appartement (optionnel)"> |
||||||
|
</div> |
||||||
|
<div style="display: flex; gap: 10px;"> |
||||||
|
<input type="text" name="postal_code" class="address-input" style="width: 25%;" placeholder="Code postal"> |
||||||
|
<input type="text" name="city" class="address-input" style="width: 25%;" placeholder="Ville"> |
||||||
|
<input type="text" name="country" class="address-input" style="width: 25%;" placeholder="Pays"> |
||||||
|
</div> |
||||||
|
<button type="submit" class="save-btn confirm-nav-button">Enregistrer</button> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
|
||||||
|
{% if order.discount_amount > 0 %} |
||||||
|
<div class="discount-section"> |
||||||
|
<div class="discount-row"> |
||||||
|
<span>Sous-total:</span> |
||||||
|
<span class="price-value">{{ order.total_price }}€</span> |
||||||
|
</div> |
||||||
|
<div class="discount-row"> |
||||||
|
<span>Réduction:</span> |
||||||
|
<span class="price-value">-{{ order.discount_amount }}€</span> |
||||||
|
</div> |
||||||
|
<div class="discount-row total-row"> |
||||||
|
<span>Total final:</span> |
||||||
|
<span class="price-value">{{ order.get_total_after_discount }}€</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% if order.coupon %} |
||||||
|
<div class="coupon-info"> |
||||||
|
Coupon appliqué: {{ order.coupon.code }} |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
|
||||||
|
<div class="order-actions"> |
||||||
|
{% if order.status == 'PENDING' or order.status == 'PAID' %} |
||||||
|
<form method="post" action="{% url 'shop:cancel_order' order.id %}" class="inline-form" onsubmit="return confirm('Êtes-vous sûr de vouloir annuler cette commande? Cette action est irréversible.');"> |
||||||
|
{% csrf_token %} |
||||||
|
<button type="submit" class="remove-btn">Annuler la commande</button> |
||||||
|
</form> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% if messages %} |
||||||
|
<div class="messages"> |
||||||
|
{% for message in messages %} |
||||||
|
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %}"> |
||||||
|
{{ message }} |
||||||
|
</div> |
||||||
|
{% endfor %} |
||||||
|
</div> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
|
||||||
|
<script> |
||||||
|
function toggleAddressForm() { |
||||||
|
const formContainer = document.getElementById('address-form-container'); |
||||||
|
const isHidden = formContainer.style.display === 'none'; |
||||||
|
formContainer.style.display = isHidden ? 'block' : 'none'; |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
{% endblock %} |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
<nav class="margin10"> |
||||||
|
<a href="{% url 'shop:product_list' %}">La Boutique</a> |
||||||
|
<a href="{% url 'shop:my_orders' %}">Mes Commandes</a> |
||||||
|
{% if user.is_authenticated %} |
||||||
|
<a href="{% url 'profile' %}">Mon compte</a> |
||||||
|
{% else %} |
||||||
|
<a href="{% url 'login' %}">Se connecter</a> |
||||||
|
{% endif %} |
||||||
|
</nav> |
||||||
@ -1,60 +1,68 @@ |
|||||||
<table class="cart-table"> |
<table class="cart-table"> |
||||||
<tbody> |
<tbody> |
||||||
{% for item in items %} |
{% for item in items %} |
||||||
<tr class="{% cycle 'odd-row' 'even-row' %}"> |
<tr class="{% cycle 'odd-row' 'even-row' %}"> |
||||||
<td class="text-left product-name" data-label="Produit">{{ item.product_title }}</td> |
<td class="text-left product-name" data-label="Produit">{{ item.product_title }}</td> |
||||||
{% if item.product_description %} |
{% if item.product_description %} |
||||||
<td class="text-left product-description" data-label="Description">{{ item.product_description }}</td> |
<td class="text-left product-description" data-label="Description">{{ item.product_description }}</td> |
||||||
{% endif %} |
{% endif %} |
||||||
<td class="product-color" data-label="Couleur"> |
<td class="product-color" data-label="Couleur"> |
||||||
<div class="color-display"> |
<div class="color-display"> |
||||||
<div class="color-sample-cart" |
<div class="color-sample-cart" |
||||||
{% if item.secondary_color_hex %} |
{% if item.secondary_color_hex %} |
||||||
style="background-image: linear-gradient(to right, {{ item.color_hex }} 50%, {{ item.secondary_color_hex }} 50%);" |
style="background-image: linear-gradient(to right, {{ item.color_hex }} 50%, {{ item.secondary_color_hex }} 50%);" |
||||||
{% else %} |
{% else %} |
||||||
style="background-color: {{ item.color_hex }};" |
style="background-color: {{ item.color_hex }};" |
||||||
{% endif %} |
{% endif %} |
||||||
></div> |
></div> |
||||||
{{ item.color_name }} | {{ item.size_name }} |
{{ item.color_name }} | {{ item.size_name }} |
||||||
</div> |
</div> |
||||||
</td> |
</td> |
||||||
<td class="product-quantity" data-label="Quantité"> |
<td class="product-quantity" data-label="Quantité"> |
||||||
{% if edit_mode %} |
{% if edit_mode %} |
||||||
<div class="quantity-controls"> |
<div class="quantity-controls"> |
||||||
<form method="post" action="{% url 'shop:update_cart_item' %}" class="quantity-form"> |
<form method="post" action="{% url 'shop:update_cart_item' %}" class="quantity-form"> |
||||||
{% csrf_token %} |
{% csrf_token %} |
||||||
<input type="hidden" name="item_id" value="{{ item.id }}"> |
<input type="hidden" name="item_id" value="{{ item.id }}"> |
||||||
<button type="submit" name="action" value="decrease" class="quantity-btn" {% if item.quantity <= 1 %}disabled{% endif %}>-</button> |
<button type="submit" name="action" value="decrease" class="quantity-btn" {% if item.quantity <= 1 %}disabled{% endif %}>-</button> |
||||||
<span class="quantity-value">{{ item.quantity }}</span> |
<span class="quantity-value">{{ item.quantity }}</span> |
||||||
<button type="submit" name="action" value="increase" class="quantity-btn">+</button> |
<button type="submit" name="action" value="increase" class="quantity-btn">+</button> |
||||||
</form> |
</form> |
||||||
</div> |
</div> |
||||||
{% else %} |
{% else %} |
||||||
<span>x {{ item.quantity }}</span> |
<span>x {{ item.quantity }}</span> |
||||||
{% endif %} |
{% endif %} |
||||||
</td> |
</td> |
||||||
<td class="price-column product-price" data-label="Prix">{{ item.total_price }} €</td> |
<td class="price-column product-price" data-label="Prix">{{ item.total_price }} €</td> |
||||||
{% if edit_mode %} |
{% if edit_mode %} |
||||||
<td class="product-actions"> |
<td class="product-actions"> |
||||||
<form method="post" action="{% url 'shop:remove_from_cart' %}" class="remove-form"> |
<form method="post" action="{% url 'shop:remove_from_cart' %}" class="remove-form"> |
||||||
{% csrf_token %} |
{% csrf_token %} |
||||||
<input type="hidden" name="item_id" value="{{ item.id }}"> |
<input type="hidden" name="item_id" value="{{ item.id }}"> |
||||||
<button type="submit" class="remove-btn">retirer</button> |
<button type="submit" class="remove-btn">retirer</button> |
||||||
</form> |
</form> |
||||||
</td> |
</td> |
||||||
{% endif %} |
{% elif cancel_mode and items.count > 1 %} |
||||||
</tr> |
<td class="product-actions"> |
||||||
{% endfor %} |
<form method="post" action="{% url 'shop:cancel_order_item' order.id item.id %}" class="remove-form" |
||||||
</tbody> |
onsubmit="return confirm('Êtes-vous sûr de vouloir annuler cet article ? {% if order.status == 'PAID' %}Un remboursement sera effectué.{% endif %}');"> |
||||||
<tfoot> |
{% csrf_token %} |
||||||
<tr> |
<button type="submit" class="remove-btn">annuler</button> |
||||||
<td class="total-quantity" data-label="total-quantity">{{ total_quantity }} produit(s)</td> |
</form> |
||||||
<td class="total-label text-left"></td> |
</td> |
||||||
<td class="total-label text-left"></td> |
{% endif %} |
||||||
<td class="price-column total-price" data-label="total-price">{{ total_price }} €</td> |
</tr> |
||||||
{% if edit_mode %} |
{% endfor %} |
||||||
<td class="total-label text-left"></td> |
</tbody> |
||||||
{% endif %} |
<tfoot> |
||||||
</tr> |
<tr> |
||||||
</tfoot> |
<td class="total-quantity" data-label="total-quantity">{{ total_quantity }} produit(s)</td> |
||||||
|
<td class="total-label text-left"></td> |
||||||
|
<td class="total-label text-left"></td> |
||||||
|
<td class="price-column total-price" data-label="total-price">{{ total_price }} €</td> |
||||||
|
{% if edit_mode or cancel_mode %} |
||||||
|
<td class="total-label text-left"></td> |
||||||
|
{% endif %} |
||||||
|
</tr> |
||||||
|
</tfoot> |
||||||
</table> |
</table> |
||||||
|
|||||||
@ -0,0 +1,18 @@ |
|||||||
|
# Generated by Django 5.1 on 2025-05-06 07:56 |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('tournaments', '0118_tournament_animation_type'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.AlterField( |
||||||
|
model_name='tournament', |
||||||
|
name='animation_type', |
||||||
|
field=models.IntegerField(choices=[(0, 'Tournoi'), (1, 'Mêlée'), (2, 'Classement'), (3, 'Consolation')], default=0), |
||||||
|
), |
||||||
|
] |
||||||
Loading…
Reference in new issue