add cart
parent
f0cf85f3fa
commit
998a530500
|
|
@ -0,0 +1,3 @@
|
||||||
|
date=$(date +%Y-%m-%d"_"%H_%M_%S)
|
||||||
|
docker-compose exec web python3 manage.py dumpdata --natural-foreign --exclude auth.permission --exclude contenttypes --indent 1 | gzip > backups/djangodump_${date}.json.gz
|
||||||
|
docker-compose exec db pg_dump -U partdoc partdoc | gzip > backups/pgdump_${date}.sql.gz
|
||||||
|
|
@ -11,7 +11,7 @@ services:
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
command: python3 ./manage.py runserver 0.0.0.0:8000
|
command: python3 ./manage.py runserver 0.0.0.0:8000
|
||||||
ports:
|
ports:
|
||||||
- 8080:8000
|
- 8081:8000
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
db:
|
db:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM alpine:3.10
|
FROM alpine:3.11
|
||||||
|
|
||||||
ADD requirements.txt /
|
ADD requirements.txt /
|
||||||
RUN apk add --update --no-cache python3 py3-psycopg2 && \
|
RUN apk add --update --no-cache python3 py3-psycopg2 && \
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Brand, Product, Version, Sketch, Part, Usage, BrandedPart, ProductUsage
|
from .models import Brand, Product, Version, Sketch, Part, Usage, BrandedPart, ProductUsage, Cart, CartEntry, Shop
|
||||||
|
|
||||||
# admin.site.register([Brand, Product, Version, Sketch, Part, Usage, BrandedPart, ProductUsage])
|
# admin.site.register([Brand, Product, Version, Sketch, Part, Usage, BrandedPart, ProductUsage])
|
||||||
admin.site.register([Brand, Product, Version, Sketch])
|
admin.site.register([Brand, Product, Version, Sketch, Shop, CartEntry])
|
||||||
|
|
||||||
|
|
||||||
class BrandedPartInline(admin.StackedInline):
|
class BrandedPartInline(admin.StackedInline):
|
||||||
|
|
@ -51,7 +51,18 @@ class BrandedPartAdmin(admin.ModelAdmin):
|
||||||
autocomplete_fields = ["parts"]
|
autocomplete_fields = ["parts"]
|
||||||
|
|
||||||
|
|
||||||
|
class CartEntryInline(admin.StackedInline):
|
||||||
|
model = CartEntry
|
||||||
|
extra = 1
|
||||||
|
raw_id_fields = ("origins",)
|
||||||
|
|
||||||
|
class CartAdmin(admin.ModelAdmin):
|
||||||
|
inlines = [CartEntryInline]
|
||||||
|
#search_fields = ["number"]
|
||||||
|
#autocomplete_fields = ["parts"]
|
||||||
|
|
||||||
admin.site.register(Usage, UsageAdmin)
|
admin.site.register(Usage, UsageAdmin)
|
||||||
admin.site.register(ProductUsage, ProductUsageAdmin)
|
admin.site.register(ProductUsage, ProductUsageAdmin)
|
||||||
admin.site.register(Part, PartAdmin)
|
admin.site.register(Part, PartAdmin)
|
||||||
admin.site.register(BrandedPart, BrandedPartAdmin)
|
admin.site.register(BrandedPart, BrandedPartAdmin)
|
||||||
|
admin.site.register(Cart, CartAdmin)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
class PartModel(models.Model):
|
class PartModel(models.Model):
|
||||||
creation = models.DateTimeField(auto_now_add=True)
|
creation = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
@ -157,3 +157,49 @@ class ProductUsage(PartModel):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
no = self.usage.part.number if self.usage else "--(part.number)--"
|
no = self.usage.part.number if self.usage else "--(part.number)--"
|
||||||
return "ProductUsage: " + self.product.name + " @ " + str(self.quantity) + "; " + str(no)
|
return "ProductUsage: " + self.product.name + " @ " + str(self.quantity) + "; " + str(no)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Shop(PartModel):
|
||||||
|
name = models.CharField(max_length=512)
|
||||||
|
url = models.URLField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
class Cart(PartModel):
|
||||||
|
name = models.CharField(max_length=512)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def add(self, product_usage):
|
||||||
|
part = product_usage.usage.part
|
||||||
|
entry = None
|
||||||
|
for i in self.entries.all():
|
||||||
|
if part == i.part:
|
||||||
|
entry = i
|
||||||
|
break
|
||||||
|
if not entry:
|
||||||
|
entry = CartEntry.objects.create(cart=self)
|
||||||
|
entry.origins.add(product_usage)
|
||||||
|
entry.save()
|
||||||
|
|
||||||
|
|
||||||
|
class CartEntry(PartModel):
|
||||||
|
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name="entries")
|
||||||
|
origins = models.ManyToManyField(ProductUsage)
|
||||||
|
shop = models.ForeignKey(Shop, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
in_cart = models.BooleanField(default=False, blank=True)
|
||||||
|
ordered = models.BooleanField(default=False, blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def part(self):
|
||||||
|
return self.origins.first().usage.part
|
||||||
|
|
||||||
|
@property
|
||||||
|
def quantity(self):
|
||||||
|
return self.origins.aggregate(sum=Sum('quantity'))["sum"]
|
||||||
|
|
||||||
|
def get_quantity(self):
|
||||||
|
return self.quantity
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
function getCookie(name) {
|
||||||
|
var cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie !== '') {
|
||||||
|
var cookies = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
|
var cookie = cookies[i].trim();
|
||||||
|
// Does this cookie string begin with the name we want?
|
||||||
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function csrfSafeMethod(method) {
|
||||||
|
// these HTTP methods do not require CSRF protection
|
||||||
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||||
|
}
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function(xhr, settings) {
|
||||||
|
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||||
|
var csrftoken = getCookie('csrftoken');
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
xhr.setRequestHeader("X-Frame-Options", "SAMEORIGIN");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function update_cart(pu_id){
|
||||||
|
var cart = $("#cart")[0].value;
|
||||||
|
console.log("cart", cart);
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "/parts/cart/add/",
|
||||||
|
data: {
|
||||||
|
"cart_name": cart,
|
||||||
|
"product_usage_id": pu_id
|
||||||
|
},
|
||||||
|
success: function(data){
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
}).done(function(msg){console.log("done" + msg);console.log(msg)})
|
||||||
|
.fail(function(msg){console.log("fail" + msg);console.log(msg)})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<h1>{{cart.name}}</h1>
|
||||||
|
<h3>entries</h3>
|
||||||
|
<ul>
|
||||||
|
{% for entry in entries %}
|
||||||
|
<li>{{entry.quantity}} -- <a href="{% url 'parts:cart_entry' cart.id entry.id %}">{{entry.part}}</a>
|
||||||
|
<ul>
|
||||||
|
{% for pu in entry.origins.all %}
|
||||||
|
<li><a href="{% url 'parts:sketch' pu.usage.sketch.id %}">{{pu.usage.sketch.name}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<h1>{{cart.name}}</h1>
|
||||||
|
<h3>entries</h3>
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
<a href="{% url 'parts:cart' cart.id %}">{{cart.name}}</a>
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
|
||||||
<h1>part {{part.number}}</h1>
|
<h1>part {{part.number}}</h1>
|
||||||
<h3>{{part.name}}</h3>
|
<h3>{{part.get_name}}</h3>
|
||||||
|
<h4>{{full_name}}</h4>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Produkt</th>
|
<th>Produkt</th>
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,11 @@
|
||||||
<li><a href="{% url 'parts:product' product.id %}">{{product.name}}</a></li>
|
<li><a href="{% url 'parts:product' product.id %}">{{product.name}}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h1>Available carts</h1>
|
||||||
|
<ul>
|
||||||
|
{% for cart in cart_list %}
|
||||||
|
<li><a href="{% url 'parts:cart' cart.id %}">{{cart.name}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
|
{% load static %}
|
||||||
|
<script type="text/javascript" src="{% static 'parts/jquery-3.2.1.min.js' %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static 'parts/update_cart.js' %}"></script>
|
||||||
|
|
||||||
<h1>{{sketch.name}}</h1>
|
<h1>{{sketch.name}}</h1>
|
||||||
<a href="{{sketch.image.url}}"><img src="{{sketch.image.url}}" /></a>
|
{% if sketch.image %}<a href="{{sketch.image.url}}"><img src="{{sketch.image.url}}" /></a> {% endif %}
|
||||||
<h2>{% for brand in sketch.get_brand %}{{brand.name}},{% endfor%} - {% for product in sketch.get_product %}{{product.name}},{% endfor%}</h2>
|
<h2>{% for brand in sketch.get_brand %}{{brand.name}},{% endfor%} - {% for product in sketch.get_product %}{{product.name}},{% endfor%}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{% for usage in sketch.usage_set.all %}
|
{% for usage in sketch.usage_set.all %}
|
||||||
<li><a href="/parts/usage/{{usage.id}}/">{{usage}}</a></li>
|
<!--<li><a href="/parts/usage/{{usage.id}}/">{{usage}}</a></li>-->
|
||||||
<li><a href="% url 'parts:usage' usage.id %">{usage}</a></li><!--TODO!-->
|
<li><button type="button" onclick="update_cart({{usage.id}})" id="update_cart_{{usage.id}}" >+</button><a href="{% url 'parts:part' usage.part.id %}">{{usage}}</a></li><!--TODO!-->
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<p>{{sketch.get_brand}}</p>
|
<p>{{sketch.get_brand}}</p>
|
||||||
<p>{{sketch.get_brand.name.foo}}</p>
|
<p>{{sketch.get_brand.name.foo}}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<label for="cart_name">cart:</label><input name="cart_name" id="cart"></input>
|
||||||
<a href="{% url "parts:continue_sketch" sketch.product_id sketch.id %}">Edit</a>
|
<a href="{% url "parts:continue_sketch" sketch.product_id sketch.id %}">Edit</a>
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,7 @@ urlpatterns = [
|
||||||
path('add/<int:product_id>/sketch/<int:sketch_id>', views.sketch_add, name="continue_sketch"),
|
path('add/<int:product_id>/sketch/<int:sketch_id>', views.sketch_add, name="continue_sketch"),
|
||||||
path('add/<int:product_id>/sketch', views.sketch_add, name="new_sketch"),
|
path('add/<int:product_id>/sketch', views.sketch_add, name="new_sketch"),
|
||||||
path('search/part/', views.part_search, name="part_search"),
|
path('search/part/', views.part_search, name="part_search"),
|
||||||
|
path('cart/add/', views.update_cart, name="cart_add"),
|
||||||
|
path('cart/<int:cart_id>/', views.cart, name="cart"),
|
||||||
|
path('cart/<int:cart_id>/entry/<int:entry_id>/', views.cart_entry, name="cart_entry"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,10 @@ ADD_SKETCH_REQUIRES = ['sketch_name', 'sketch_number', '']
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
product_list = Product.objects.all()
|
product_list = Product.objects.all()
|
||||||
context = {'product_list': product_list}
|
context = {
|
||||||
|
'product_list': product_list,
|
||||||
|
'cart_list': Cart.objects.all()
|
||||||
|
}
|
||||||
return render(request, 'parts/products.html', context)
|
return render(request, 'parts/products.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -31,7 +34,8 @@ def sketch(request, sketch_id):
|
||||||
|
|
||||||
def __part_view(request, part):
|
def __part_view(request, part):
|
||||||
sketches = part.usage_set.values('sketch', 'sketch_number', 'sketch__name', 'sketch__product__name', 'sketch__product__id').annotate(qty=Sum('productusage__quantity'))
|
sketches = part.usage_set.values('sketch', 'sketch_number', 'sketch__name', 'sketch__product__name', 'sketch__product__id').annotate(qty=Sum('productusage__quantity'))
|
||||||
context = {'part': part, 'sketches': sketches}
|
full_name = part.get_name(full=True)
|
||||||
|
context = {'part': part, 'sketches': sketches, 'full_name': full_name}
|
||||||
return render(request, 'parts/part.html', context)
|
return render(request, 'parts/part.html', context)
|
||||||
|
|
||||||
def part(request, part_id):
|
def part(request, part_id):
|
||||||
|
|
@ -179,3 +183,28 @@ def get_quantity(qnty_str):
|
||||||
def is_exact_sketchnumber(sketch_number):
|
def is_exact_sketchnumber(sketch_number):
|
||||||
approximate = ("ähn", "vgl", "~", "zu")
|
approximate = ("ähn", "vgl", "~", "zu")
|
||||||
return not any([i in sketch_number for i in approximate])
|
return not any([i in sketch_number for i in approximate])
|
||||||
|
|
||||||
|
|
||||||
|
def update_cart(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
keys = ["cart_name", "product_usage_id"]
|
||||||
|
if all([key in request.POST for key in keys]):
|
||||||
|
cart, _ = Cart.objects.get_or_create(name=request.POST["cart_name"])
|
||||||
|
pu = ProductUsage.objects.get(usage__id=request.POST["product_usage_id"])
|
||||||
|
cart.add(pu)
|
||||||
|
return HttpResponse('{"success": true}')
|
||||||
|
return HttpResponse('{"success": false}')
|
||||||
|
|
||||||
|
|
||||||
|
def cart(request, cart_id):
|
||||||
|
cart = Cart.objects.get(id=cart_id)
|
||||||
|
entries = cart.entries.all()
|
||||||
|
context = {'cart': cart, "entries": entries}
|
||||||
|
return render(request, 'parts/cart.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
def cart_entry(request, cart_id, entry_id):
|
||||||
|
cart = Cart.objects.get(id=cart_id)
|
||||||
|
entry = CartEntry.objects.get(id=entry_id)
|
||||||
|
context = {'cart': cart, 'entry': entry}
|
||||||
|
return render(request, 'parts/cart_entry.html', context)
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
django==3.0
|
django==3.0.5
|
||||||
psycopg2==2.8.4
|
psycopg2==2.8.4
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue