from django.shortcuts import render from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.views.generic import ListView from django.db import transaction from .models import ( Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar) from .forms import ( ImportProductsForm, ImportCustomersForm, PurchaseForm, SaleLineFormSet, PurchaseSummaryForm) import csv import io import json from decimal import Decimal from datetime import datetime class DecimalEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Decimal): return float(obj) return json.JSONEncoder.default(self, obj) def index(request): return render(request, 'don_confiao/index.html') def buy(request): if request.method == "POST": sale_form = PurchaseForm(request.POST) line_formset = SaleLineFormSet(request.POST) sale_summary_form = PurchaseSummaryForm(request.POST) forms_are_valid = all([ sale_form.is_valid(), line_formset.is_valid(), sale_summary_form.is_valid() ]) payment_method = request.POST.get('payment_method') valid_payment_methods = [PaymentMethods.CASH] valid_payment_method = payment_method in valid_payment_methods if forms_are_valid: with transaction.atomic(): sale = sale_form.save() line_formset.instance = sale line_formset.save() Payment.total_payment_from_sale( payment_method, sale ) return HttpResponseRedirect("compras") else: sale_form = PurchaseForm() line_formset = SaleLineFormSet() sale_summary_form = PurchaseSummaryForm() return render( request, 'don_confiao/purchase.html', { 'sale_form': sale_form, 'linea_formset': line_formset, 'summary_form': sale_summary_form, 'list_products': json.dumps(Product.to_list(), cls=DecimalEncoder), } ) def purchases(request): purchases = Sale.objects.all() context = { "purchases": purchases, } return render(request, 'don_confiao/purchases.html', context) def products(request): return JsonResponse(Product.to_list(), safe=False) def import_products(request): if request.method == "POST": form = ImportProductsForm(request.POST, request.FILES) if form.is_valid(): handle_import_products_file(request.FILES["csv_file"]) return HttpResponseRedirect("productos") else: form = ImportProductsForm() return render( request, "don_confiao/import_products.html", {'form': form} ) def import_customers(request): if request.method == "POST": form = ImportCustomersForm(request.POST, request.FILES) if form.is_valid(): handle_import_customers_file(request.FILES["csv_file"]) return HttpResponseRedirect("productos") else: form = ImportCustomersForm() return render( request, "don_confiao/import_customers.html", {'form': form} ) def reconciliate_jar(request): date_format = '%Y-%m-%dT%H:%M' if request.method == 'POST': content = request.POST.dict() content['purchases'] = json.loads(content.get('purchases'))#machete por error al codificar el json en el test reconciliation = ReconciliationJar() reconciliation.date_time = content.get('date_time') reconciliation.cashman = content.get('cashman') reconciliation.total_cash_purchases = float(content.get('total_cash_purchases')) reconciliation.cash_taken = float(content.get('cash_taken')) reconciliation.cash_discrepancy = float(content.get('cash_discrepancy')) purchases = Sale.objects.filter(pk__in=content.get('purchases')) if reconciliation.total_cash_purchases != sum(p.get_total() for p in purchases): return JsonResponse( {'error': 'total_cash_purchases not equal to sum of all purchases.'}, status=400 ) reconciliation.clean() reconciliation.save() for purchase in purchases: purchase.reconciliation = reconciliation purchase.clean() purchase.save() return JsonResponse( {'id': reconciliation.id}, safe=False ) def reconciliations(request): return HttpResponse('

Reconciliaciones

') def purchase_summary(request, id): purchase = Sale.objects.get(pk=id) return render( request, "don_confiao/purchase_summary.html", { "purchase": purchase } ) def purchase_json_summary(request, id): purchase = Sale.objects.get(pk=id) lines = [] for line in purchase.saleline_set.all(): lines.append({ 'product': { 'id': line.product.id, 'name': line.product.name, }, 'quantity': line.quantity, 'unit_price': line.unit_price, 'description': line.description, }) to_response = { 'id': purchase.id, 'date': purchase.date, 'customer': { 'id': purchase.customer.id, 'name': purchase.customer.name, # 'phone': _mask_phone(purchase.customer.phone) }, 'payment_method': purchase.payment_method, 'set_lines': lines, } return JsonResponse(to_response, safe=False) def payment_methods_to_select(request): methods = [ {'text': choice[1], 'value': choice[0]} for choice in PaymentMethods.choices ] return JsonResponse(methods, safe=False) def sales_for_reconciliation(request): sales = Sale.objects.filter(reconciliation=None) grouped_sales = {} for sale in sales: if sale.payment_method not in grouped_sales.keys(): grouped_sales[sale.payment_method] = [] grouped_sales[sale.payment_method].append({ 'id': sale.id, 'date': sale.date, 'payment_method': sale.payment_method, 'customer': { 'id': sale.customer.id, 'name': sale.customer.name, }, 'total': sale.get_total(), }) return JsonResponse(grouped_sales, safe=False) def _mask_phone(phone): digits = str(phone)[-3:] if phone else " " * 3 return "X" * 7 + digits def _categories_from_csv_string(categories_string, separator="&"): categories = categories_string.split(separator) clean_categories = [c.strip() for c in categories] return [_category_from_name(category) for category in clean_categories] def _category_from_name(name): return ProductCategory.objects.get_or_create(name=name)[0] def handle_import_products_file(csv_file): data = io.StringIO(csv_file.read().decode('utf-8')) reader = csv.DictReader(data, quotechar='"') for row in reader: product, created = Product.objects.update_or_create( name=row['producto'], defaults={ 'price': row['precio'], 'measuring_unit': row['unidad'] } ) categories = _categories_from_csv_string(row["categorias"]) product.categories.clear() for category in categories: product.categories.add(category) def handle_import_customers_file(csv_file): data = io.StringIO(csv_file.read().decode('utf-8')) reader = csv.DictReader(data, quotechar='"') for row in reader: customer, created = Customer.objects.update_or_create( name=row['nombre'], defaults={ 'email': row['correo'], 'phone': row['telefono'] } ) def exportar_ventas_para_tryton(request): tryton_sales_header = [ "Tercero", "Dirección de facturación", "Dirección de envío", "Descripción", "Referencia", "Fecha venta", "Plazo de pago", "Almacén", "Moneda", "Líneas/Producto", "Líneas/Cantidad", "Líneas/Precio unitario", "Líneas/Unidad", "Empresa", "Tienda", "Terminal de venta", "Autorecogida", "Comentario" ] if request.method == "GET": response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = "attachment; filename=sales.csv" writer = csv.writer(response) writer.writerow(tryton_sales_header) sales = Sale.objects.all() for sale in sales: sale_lines = SaleLine.objects.filter(sale=sale.id) if not sale_lines: continue lines = [] first_sale_line = sale_lines[0] customer_info = [sale.customer.name] * 3 + [sale.description] * 2 first_line = customer_info + [ sale.date, "Contado", "Almacén", "Peso colombiano", first_sale_line.product.name, first_sale_line.quantity, "Unidad", first_sale_line.unit_price, "TIENDA LA ILUSIÓN", "Tienda La Ilusion", "La Ilusion", True, sale.description] lines.append(first_line) for line in sale_lines[1:]: lines.append([""]*9+[ line.product.name, line.quantity, line.unit_price, "Unidad"]+[""]*5) for row in lines: writer.writerow(row) return response class ProductListView(ListView): model = Product template_model = 'don_confiao/product_list.html' def get_queryset(self): name = self.request.GET.get('name') if name: return Product.objects.filter(name__icontains=name) return Product.objects.all()