diff --git a/assets/js/formset.js b/assets/js/formset.js index cedfc64..9cdd19e 100644 --- a/assets/js/formset.js +++ b/assets/js/formset.js @@ -6,6 +6,20 @@ let formset = function() { let totalFormCounter; let arr = [] + let subTotalComputation = function(){ + // Sub-t0tal computation + $('.field-amount').each(function(counter){ + arr[counter] = Number( $(this).text() ) + }); + let subTotal = 0 + let totalForm = Number( $('#id_form-TOTAL_FORMS').val() ); + for(let counter=0; counter' - +'
' - +'
' - +'
' - +'Edit' - +'Delete' - +'|Generate PDF|' - +' Send' - +'
' - +'
' - +'
' - +'' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.invoice_number - +'
' - +'
' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.client - +'
' - +'
' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.item - +'
' - +'
' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.invoice_date - +'
' - +'
' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.due_date - +'
' - +'
' - +'
' - +'
' - +' ' - +'
' - +'
' - +obj[data].fields.remarks - +'
' - +'
' - ) - } - }); + let paymentStat = ''; + if (invData.fields.payment_status == false){ + paymentStat = 'unpaid'; + } else if (invData.fields.payment_status == true){ + paymentStat = 'paid'; + } + + let invDueDateData = new Date(invData.fields.due_date); + let invDateData = new Date(invData.fields.invoice_date); + + let arrInvDate = []; + let arrDueDate = []; + let invoiceDate = ''; + let invoiceDueDate = ''; + arrInvDate = String(invDateData).split(' '); + arrDueDate = String(invDueDateData).split(' '); + invoiceDate = arrInvDate[1]+' '+arrInvDate[2]+', '+arrInvDate[3]; + invoiceDueDate = arrDueDate[1]+' '+arrDueDate[2]+', '+arrDueDate[3]; + + invNum.text(resp.prefix.toUpperCase()+': '+resp.invoice_number); + invDesc.text(invData.fields.description.charAt(0).toUpperCase() + + invData.fields.description.slice(1).toLowerCase() + ); + invClient.text(resp.client.toLowerCase() + .replace(/\b[a-z]/g, function(letter) { + return letter.toUpperCase(); + }) + ); + invPayStat.text(paymentStat.charAt(0).toUpperCase()+ paymentStat.slice(1).toLowerCase()); + invDueDate.text(invoiceDueDate); + invDate.text(invoiceDate); + invRem.text(invData.fields.remarks.charAt(0).toUpperCase() + + invData.fields.remarks.slice(1).toLowerCase() + ); + invSubTotal.text(invData.fields.subtotal); + invTotal.text(invData.fields.subtotal); + + if (invItems.length) { + itemsTbody.html(''); + for (var i = invItems.length - 1; i >= 0; i--) { + let newRow = itemsRow.clone(); + newRow.removeClass('hidden'); + newRow.children('.itemDesc').html(invItems[i].fields.description); + newRow.children('.itemQty').html(invItems[i].fields.quantity); + newRow.children('.itemRate').html(invItems[i].fields.rate); + newRow.children('.itemAmount').html(invItems[i].fields.amount); + itemsTbody.append(newRow); + } + } + }, + }) }); }); diff --git a/invoices/forms.py b/invoices/forms.py index 0979643..ad9bae1 100644 --- a/invoices/forms.py +++ b/invoices/forms.py @@ -29,6 +29,7 @@ class Meta: 'remarks', 'description', 'payment_status', + 'subtotal', ) def __init__(self,*args, **kwargs): @@ -117,11 +118,8 @@ def clean(self): for count,form in enumerate(self.forms): if not form.data['form-'+str(count)+'-description']: - print("not description") raise forms.ValidationError("Description is required!") if not form.data['form-'+str(count)+'-quantity']: - print("not qty") raise forms.ValidationError("Quantity is required!") if not form.data['form-'+str(count)+'-rate']: - print("not rate") raise forms.ValidationError("Rate is required!") diff --git a/invoices/models.py b/invoices/models.py index 0592182..a3260b0 100644 --- a/invoices/models.py +++ b/invoices/models.py @@ -34,15 +34,13 @@ class Invoice(models.Model): payment_status = models.BooleanField( default=False) pdf = models.FileField(upload_to=get_invoice_directory,null=True, blank=True) remarks = models.TextField(max_length=255,null=True, blank=True) + subtotal = models.PositiveIntegerField() status = models.CharField(max_length=10, choices=STATUS, default='draft') class Meta: unique_together = ('invoice_number', 'company') def __str__(self): - return f"{self.invoice_number}" - - def get_invoice_number(self): return f"{self.invoice_number}".zfill(9) diff --git a/invoices/views.py b/invoices/views.py index 47a54c8..e039e2d 100644 --- a/invoices/views.py +++ b/invoices/views.py @@ -117,9 +117,11 @@ def get(self, *args, **kwargs): """ query = self.request.GET.get("q") if query: - invoices = invoices.filter(invoice_number__icontains=query) + invoices = invoices.filter(invoice_number__icontains=query + ).order_by('-date_updated') else: - invoices = Invoice.objects.filter(company=self.request.user.company) + invoices = Invoice.objects.filter(company=self.request.user.company + ).order_by('-date_updated') context = {} context['client_form'] = ClientForm() ItemFormSet = formset_factory(ItemForm, formset=BaseItemFormSet) @@ -170,7 +172,8 @@ def post(self, *args, **kwargs): messages.success(self.request, 'Invoice is successfully Added') return redirect('invoices') else: - invoices = Invoice.objects.filter(company=self.request.user.company) + invoices = Invoice.objects.filter(company=self.request.user.company + ).order_by('-date_updated') context = {} context['invoices'] = invoices context['invoice_form'] = invoice_form @@ -204,15 +207,23 @@ class InvoiceAjaxView(UserIsOwnerMixin, View): """ def get(self, *args, **kwargs): - """Display pdf in browser + """Display invoice details """ invoice = get_object_or_404(Invoice, id=kwargs['invoice_id']) - data = serializers.serialize('json', [invoice]) - return JsonResponse({'invoice': data, - }, - safe = False, - status=200 - ) + invoice_number = str(invoice) + client = str(invoice.client) + items = Item.objects.filter(invoice=kwargs['invoice_id']) + invoiceData = serializers.serialize('json', [invoice]) + itemsData = serializers.serialize('json', items) + data = { + 'client': client, + 'invoice_number': invoice_number, + 'invoice': invoiceData, + 'items': itemsData, + 'prefix': invoice.client.get_prefix(), + } + return JsonResponse(data, safe = False, status=200) + class InvoiceAddView(LoginRequiredMixin,TemplateView): diff --git a/templates/invoices/all_invoice.html b/templates/invoices/all_invoice.html index 09dfe9b..b969968 100644 --- a/templates/invoices/all_invoice.html +++ b/templates/invoices/all_invoice.html @@ -13,25 +13,131 @@ {% endif %} -

Invoice

+ {% if not invoices %} + No invoices yet + {% endif %} {% for invoice in invoices %}
-
+ +
-
{{ invoice.client.client_company }}
-
{{ invoice.get_invoice_number }}
-
{{ invoice.due_date }}
-
{{ invoice.status }}
+
{{ invoice.client.client_company|title }}
+
{{ invoice.client.get_prefix|upper }}: {{ invoice }}
+
{{ invoice.due_date|date:"M d, Y" }}
+
+ {% if invoice.status == 'sent' %} + |{{ invoice.status|title }} + {% elif invoice.status == 'draft' %} + |{{ invoice.status|title }} + {% endif %} +
{% endfor %}
-
+ + +
{% csrf_token %}
@@ -123,48 +229,41 @@

New Invoice


{{ formset.management_form }} - {% for form in formset %} - - -
- +
{% if formset.non_form_errors %} - - {{ form.non_form_errors }} - {% for error in formset.non_form_errors %} - {{ error|escape }} - {% endfor %} - {% endif %} - - - {% if form.description.errors %} - - [{{ forloop.counter }}]description error: {{ form.description.errors.as_text }} - -
- {% endif %} - {% if form.quantity.errors %} - - [{{ forloop.counter }}]quantity error: {{ form.quantity.errors.as_text }} - -
- {% endif %} - {% if form.rate.errors %} - - [{{ forloop.counter }}]rate error: {{ form.rate.errors.as_text }} - -
- {% endif %} - {% if form.amount.errors %} - - [{{ forloop.counter }}]amount error: {{ form.amount.errors.as_text }} - -
- {% endif %} + {{ form.non_form_errors }} + {% for error in formset.non_form_errors %} + {{ error|escape }} + {% endfor %} + {% endif %} + + {% if form.description.errors %} + + [{{ forloop.counter }}]description error: {{ form.description.errors.as_text }} + +
+ {% endif %} + {% if form.quantity.errors %} + + [{{ forloop.counter }}]quantity error: {{ form.quantity.errors.as_text }} + +
+ {% endif %} + {% if form.rate.errors %} + + [{{ forloop.counter }}]rate error: {{ form.rate.errors.as_text }} + +
+ {% endif %} + {% if form.amount.errors %} + + [{{ forloop.counter }}]amount error: {{ form.amount.errors.as_text }} + +
+ {% endif %}
-
{{ form.description|attr:"class:form-control"|attr:"required:True" }} @@ -181,46 +280,36 @@

New Invoice


- - - - - - {% endfor %}
-
-
-
-
-
-
-
- -
-
- -
-
-
-
- {{ invoice_form.remarks|attr:"placeholder:Remarks"|attr:"class:form-control"}}
-
{{ invoice_form.remarks.errors.as_text }}
-
-
-
+
+
{{ invoice_form.subtotal|attr:"val:0"|attr:"hidden" }}
+ +
+
+
+ +
+
-

-
-
- - +
+ {{ invoice_form.remarks|attr:"placeholder:Remarks"|attr:"class:form-control"}}
+
{{ invoice_form.remarks.errors.as_text }}
-
-
+
+
+

+
+
+ + +
+
+
+
@@ -338,7 +427,7 @@
- {% endblock %} +{% endblock %} {% block js %}