mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Use custom inputs for date picker and amounts
This commit is contained in:
		@@ -2,11 +2,15 @@
 | 
				
			|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
 | 
					 | 
				
			||||||
from activity.models import Activity
 | 
					from activity.models import Activity
 | 
				
			||||||
 | 
					from note_kfet.inputs import DateTimePickerInput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityForm(forms.ModelForm):
 | 
					class ActivityForm(forms.ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Activity
 | 
					        model = Activity
 | 
				
			||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					        widgets = {
 | 
				
			||||||
 | 
					            "date_start": DateTimePickerInput(),
 | 
				
			||||||
 | 
					            "date_end": DateTimePickerInput(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.contrib.auth.mixins import LoginRequiredMixin
 | 
				
			||||||
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
 | 
					from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from django_tables2.views import SingleTableView
 | 
					from django_tables2.views import SingleTableView
 | 
				
			||||||
@@ -9,12 +10,12 @@ from .forms import ActivityForm
 | 
				
			|||||||
from .models import Activity
 | 
					from .models import Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityCreateView(CreateView):
 | 
					class ActivityCreateView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    form_class = ActivityForm
 | 
					    form_class = ActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityListView(SingleTableView):
 | 
					class ActivityListView(LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
@@ -25,14 +26,14 @@ class ActivityListView(SingleTableView):
 | 
				
			|||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityDetailView(DetailView):
 | 
					class ActivityDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityUpdateView(UpdateView):
 | 
					class ActivityUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    form_class = ActivityForm
 | 
					    form_class = ActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityEntryView(TemplateView):
 | 
					class ActivityEntryView(LoginRequiredMixin, TemplateView):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,10 +18,5 @@ def pretty_money(value):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def cents_to_euros(value):
 | 
					 | 
				
			||||||
    return "{:.02f}".format(value / 100) if value else ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
register = template.Library()
 | 
					register = template.Library()
 | 
				
			||||||
register.filter('pretty_money', pretty_money)
 | 
					register.filter('pretty_money', pretty_money)
 | 
				
			||||||
register.filter('cents_to_euros', cents_to_euros)
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _
 | 
				
			|||||||
from django.views.generic import CreateView, UpdateView
 | 
					from django.views.generic import CreateView, UpdateView
 | 
				
			||||||
from django_tables2 import SingleTableView
 | 
					from django_tables2 import SingleTableView
 | 
				
			||||||
from django.urls import reverse_lazy
 | 
					from django.urls import reverse_lazy
 | 
				
			||||||
 | 
					from note_kfet.inputs import AmountInput
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import TransactionTemplateForm
 | 
					from .forms import TransactionTemplateForm
 | 
				
			||||||
@@ -40,6 +41,7 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
        context['title'] = _('Transfer money')
 | 
					        context['title'] = _('Transfer money')
 | 
				
			||||||
 | 
					        context['amount_widget'] = AmountInput(attrs={"id": "amount"})
 | 
				
			||||||
        context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk
 | 
					        context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk
 | 
				
			||||||
        context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk
 | 
					        context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk
 | 
				
			||||||
        context['special_types'] = NoteSpecial.objects.order_by("special_type").all()
 | 
					        context['special_types'] = NoteSpecial.objects.order_by("special_type").all()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ from crispy_forms.helper import FormHelper
 | 
				
			|||||||
from crispy_forms.layout import Submit
 | 
					from crispy_forms.layout import Submit
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					from note_kfet.inputs import DatePickerInput, AmountInput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
					from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,7 +20,7 @@ class InvoiceForm(forms.ModelForm):
 | 
				
			|||||||
    # Django forms don't support date fields. We have to add it manually
 | 
					    # Django forms don't support date fields. We have to add it manually
 | 
				
			||||||
    date = forms.DateField(
 | 
					    date = forms.DateField(
 | 
				
			||||||
        initial=datetime.date.today,
 | 
					        initial=datetime.date.today,
 | 
				
			||||||
        widget=forms.TextInput(attrs={'type': 'date'})
 | 
					        widget=DatePickerInput()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def clean_date(self):
 | 
					    def clean_date(self):
 | 
				
			||||||
@@ -30,12 +31,21 @@ class InvoiceForm(forms.ModelForm):
 | 
				
			|||||||
        exclude = ('bde', )
 | 
					        exclude = ('bde', )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProductForm(forms.ModelForm):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = Product
 | 
				
			||||||
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					        widgets = {
 | 
				
			||||||
 | 
					            "amount": AmountInput()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Add a subform per product in the invoice form, and manage correctly the link between the invoice and
 | 
					# Add a subform per product in the invoice form, and manage correctly the link between the invoice and
 | 
				
			||||||
# its products. The FormSet will search automatically the ForeignKey in the Product model.
 | 
					# its products. The FormSet will search automatically the ForeignKey in the Product model.
 | 
				
			||||||
ProductFormSet = forms.inlineformset_factory(
 | 
					ProductFormSet = forms.inlineformset_factory(
 | 
				
			||||||
    Invoice,
 | 
					    Invoice,
 | 
				
			||||||
    Product,
 | 
					    Product,
 | 
				
			||||||
    fields='__all__',
 | 
					    form=ProductForm,
 | 
				
			||||||
    extra=1,
 | 
					    extra=1,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,18 +50,8 @@ class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        ret = super().form_valid(form)
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        kwargs = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # The user type amounts in cents. We convert it in euros.
 | 
					 | 
				
			||||||
        for key in self.request.POST:
 | 
					 | 
				
			||||||
            value = self.request.POST[key]
 | 
					 | 
				
			||||||
            if key.endswith("amount") and value:
 | 
					 | 
				
			||||||
                kwargs[key] = str(int(100 * float(value)))
 | 
					 | 
				
			||||||
            elif value:
 | 
					 | 
				
			||||||
                kwargs[key] = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # For each product, we save it
 | 
					        # For each product, we save it
 | 
				
			||||||
        formset = ProductFormSet(kwargs, instance=form.instance)
 | 
					        formset = ProductFormSet(self.request.POST, instance=form.instance)
 | 
				
			||||||
        if formset.is_valid():
 | 
					        if formset.is_valid():
 | 
				
			||||||
            for f in formset:
 | 
					            for f in formset:
 | 
				
			||||||
                # We don't save the product if the designation is not entered, ie. if the line is empty
 | 
					                # We don't save the product if the designation is not entered, ie. if the line is empty
 | 
				
			||||||
@@ -112,16 +102,7 @@ class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        ret = super().form_valid(form)
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        kwargs = {}
 | 
					        formset = ProductFormSet(self.request.POST, instance=form.instance)
 | 
				
			||||||
        # The user type amounts in cents. We convert it in euros.
 | 
					 | 
				
			||||||
        for key in self.request.POST:
 | 
					 | 
				
			||||||
            value = self.request.POST[key]
 | 
					 | 
				
			||||||
            if key.endswith("amount") and value:
 | 
					 | 
				
			||||||
                kwargs[key] = str(int(100 * float(value)))
 | 
					 | 
				
			||||||
            elif value:
 | 
					 | 
				
			||||||
                kwargs[key] = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        formset = ProductFormSet(kwargs, instance=form.instance)
 | 
					 | 
				
			||||||
        saved = []
 | 
					        saved = []
 | 
				
			||||||
        # For each product, we save it
 | 
					        # For each product, we save it
 | 
				
			||||||
        if formset.is_valid():
 | 
					        if formset.is_valid():
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										280
									
								
								note_kfet/inputs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								note_kfet/inputs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,280 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					This file comes from the project `django-bootstrap-datepicker-plus` available on Github:
 | 
				
			||||||
 | 
					https://github.com/monim67/django-bootstrap-datepicker-plus
 | 
				
			||||||
 | 
					This is distributed under Apache License 2.0.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This adds datetime pickers with bootstrap.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Contains Base Date-Picker input class for widgets of this package."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from json import dumps as json_dumps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.forms.widgets import DateTimeBaseInput, NumberInput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AmountInput(NumberInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    This input type lets the user type amounts in euros, but forms receive data in cents
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    template_name = "note/amount_input.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def format_value(self, value):
 | 
				
			||||||
 | 
					        return None if value is None or value == "" else "{:.02f}".format(value / 100, )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def value_from_datadict(self, data, files, name):
 | 
				
			||||||
 | 
					        val = super().value_from_datadict(data, files, name)
 | 
				
			||||||
 | 
					        return str(int(100 * float(val))) if val else val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DatePickerDictionary:
 | 
				
			||||||
 | 
					    """Keeps track of all date-picker input classes."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _i = 0
 | 
				
			||||||
 | 
					    items = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def generate_id(cls):
 | 
				
			||||||
 | 
					        """Return a unique ID for each date-picker input class."""
 | 
				
			||||||
 | 
					        cls._i += 1
 | 
				
			||||||
 | 
					        return 'dp_%s' % cls._i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BasePickerInput(DateTimeBaseInput):
 | 
				
			||||||
 | 
					    """Base Date-Picker input class for widgets of this package."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template_name = 'bootstrap_datepicker_plus/date_picker.html'
 | 
				
			||||||
 | 
					    picker_type = 'DATE'
 | 
				
			||||||
 | 
					    format = '%Y-%m-%d'
 | 
				
			||||||
 | 
					    config = {}
 | 
				
			||||||
 | 
					    _default_config = {
 | 
				
			||||||
 | 
					        'id': None,
 | 
				
			||||||
 | 
					        'picker_type': None,
 | 
				
			||||||
 | 
					        'linked_to': None,
 | 
				
			||||||
 | 
					        'options': {}  # final merged options
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    options = {}  # options extended by user
 | 
				
			||||||
 | 
					    options_param = {}  # options passed as parameter
 | 
				
			||||||
 | 
					    _default_options = {
 | 
				
			||||||
 | 
					        'showClose': True,
 | 
				
			||||||
 | 
					        'showClear': True,
 | 
				
			||||||
 | 
					        'showTodayButton': True,
 | 
				
			||||||
 | 
					        "locale": "fr",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # source: https://github.com/tutorcruncher/django-bootstrap3-datetimepicker
 | 
				
			||||||
 | 
					    # file: /blob/31fbb09/bootstrap3_datetime/widgets.py#L33
 | 
				
			||||||
 | 
					    format_map = (
 | 
				
			||||||
 | 
					        ('DDD', r'%j'),
 | 
				
			||||||
 | 
					        ('DD', r'%d'),
 | 
				
			||||||
 | 
					        ('MMMM', r'%B'),
 | 
				
			||||||
 | 
					        ('MMM', r'%b'),
 | 
				
			||||||
 | 
					        ('MM', r'%m'),
 | 
				
			||||||
 | 
					        ('YYYY', r'%Y'),
 | 
				
			||||||
 | 
					        ('YY', r'%y'),
 | 
				
			||||||
 | 
					        ('HH', r'%H'),
 | 
				
			||||||
 | 
					        ('hh', r'%I'),
 | 
				
			||||||
 | 
					        ('mm', r'%M'),
 | 
				
			||||||
 | 
					        ('ss', r'%S'),
 | 
				
			||||||
 | 
					        ('a', r'%p'),
 | 
				
			||||||
 | 
					        ('ZZ', r'%z'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Media:
 | 
				
			||||||
 | 
					        """JS/CSS resources needed to render the date-picker calendar."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        js = (
 | 
				
			||||||
 | 
					            'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/'
 | 
				
			||||||
 | 
					            'moment-with-locales.min.js',
 | 
				
			||||||
 | 
					            'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/'
 | 
				
			||||||
 | 
					            '4.17.47/js/bootstrap-datetimepicker.min.js',
 | 
				
			||||||
 | 
					            'bootstrap_datepicker_plus/js/datepicker-widget.js'
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        css = {'all': (
 | 
				
			||||||
 | 
					            'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/'
 | 
				
			||||||
 | 
					            '4.17.47/css/bootstrap-datetimepicker.css',
 | 
				
			||||||
 | 
					            'bootstrap_datepicker_plus/css/datepicker-widget.css'
 | 
				
			||||||
 | 
					        ), }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def format_py2js(cls, datetime_format):
 | 
				
			||||||
 | 
					        """Convert python datetime format to moment datetime format."""
 | 
				
			||||||
 | 
					        for js_format, py_format in cls.format_map:
 | 
				
			||||||
 | 
					            datetime_format = datetime_format.replace(py_format, js_format)
 | 
				
			||||||
 | 
					        return datetime_format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def format_js2py(cls, datetime_format):
 | 
				
			||||||
 | 
					        """Convert moment datetime format to python datetime format."""
 | 
				
			||||||
 | 
					        for js_format, py_format in cls.format_map:
 | 
				
			||||||
 | 
					            datetime_format = datetime_format.replace(js_format, py_format)
 | 
				
			||||||
 | 
					        return datetime_format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, attrs=None, format=None, options=None):
 | 
				
			||||||
 | 
					        """Initialize the Date-picker widget."""
 | 
				
			||||||
 | 
					        self.format_param = format
 | 
				
			||||||
 | 
					        self.options_param = options if options else {}
 | 
				
			||||||
 | 
					        self.config = self._default_config.copy()
 | 
				
			||||||
 | 
					        self.config['id'] = DatePickerDictionary.generate_id()
 | 
				
			||||||
 | 
					        self.config['picker_type'] = self.picker_type
 | 
				
			||||||
 | 
					        self.config['options'] = self._calculate_options()
 | 
				
			||||||
 | 
					        attrs = attrs if attrs else {}
 | 
				
			||||||
 | 
					        if 'class' not in attrs:
 | 
				
			||||||
 | 
					            attrs['class'] = 'form-control'
 | 
				
			||||||
 | 
					        super().__init__(attrs, self._calculate_format())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _calculate_options(self):
 | 
				
			||||||
 | 
					        """Calculate and Return the options."""
 | 
				
			||||||
 | 
					        _options = self._default_options.copy()
 | 
				
			||||||
 | 
					        _options.update(self.options)
 | 
				
			||||||
 | 
					        if self.options_param:
 | 
				
			||||||
 | 
					            _options.update(self.options_param)
 | 
				
			||||||
 | 
					        return _options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _calculate_format(self):
 | 
				
			||||||
 | 
					        """Calculate and Return the datetime format."""
 | 
				
			||||||
 | 
					        _format = self.format_param if self.format_param else self.format
 | 
				
			||||||
 | 
					        if self.config['options'].get('format'):
 | 
				
			||||||
 | 
					            _format = self.format_js2py(self.config['options'].get('format'))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.config['options']['format'] = self.format_py2js(_format)
 | 
				
			||||||
 | 
					        return _format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context(self, name, value, attrs):
 | 
				
			||||||
 | 
					        """Return widget context dictionary."""
 | 
				
			||||||
 | 
					        context = super().get_context(
 | 
				
			||||||
 | 
					            name, value, attrs)
 | 
				
			||||||
 | 
					        context['widget']['attrs']['dp_config'] = json_dumps(self.config)
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start_of(self, event_id):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set Date-Picker as the start-date of a date-range.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            - event_id (string): User-defined unique id for linking two fields
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        DatePickerDictionary.items[str(event_id)] = self
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def end_of(self, event_id, import_options=True):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set Date-Picker as the end-date of a date-range.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            - event_id (string): User-defined unique id for linking two fields
 | 
				
			||||||
 | 
					            - import_options (bool): inherit options from start-date input,
 | 
				
			||||||
 | 
					              default: TRUE
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        event_id = str(event_id)
 | 
				
			||||||
 | 
					        if event_id in DatePickerDictionary.items:
 | 
				
			||||||
 | 
					            linked_picker = DatePickerDictionary.items[event_id]
 | 
				
			||||||
 | 
					            self.config['linked_to'] = linked_picker.config['id']
 | 
				
			||||||
 | 
					            if import_options:
 | 
				
			||||||
 | 
					                backup_moment_format = self.config['options']['format']
 | 
				
			||||||
 | 
					                self.config['options'].update(linked_picker.config['options'])
 | 
				
			||||||
 | 
					                self.config['options'].update(self.options_param)
 | 
				
			||||||
 | 
					                if self.format_param or 'format' in self.options_param:
 | 
				
			||||||
 | 
					                    self.config['options']['format'] = backup_moment_format
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.format = linked_picker.format
 | 
				
			||||||
 | 
					            # Setting useCurrent is necessary, see following issue
 | 
				
			||||||
 | 
					            # https://github.com/Eonasdan/bootstrap-datetimepicker/issues/1075
 | 
				
			||||||
 | 
					            self.config['options']['useCurrent'] = False
 | 
				
			||||||
 | 
					            self._link_to(linked_picker)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise KeyError(
 | 
				
			||||||
 | 
					                'start-date not specified for event_id "%s"' % event_id)
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _link_to(self, linked_picker):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Executed when two date-inputs are linked together.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This method for sub-classes to override to customize the linking.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DatePickerInput(BasePickerInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Widget to display a Date-Picker Calendar on a DateField property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Args:
 | 
				
			||||||
 | 
					        - attrs (dict): HTML attributes of rendered HTML input
 | 
				
			||||||
 | 
					        - format (string): Python DateTime format eg. "%Y-%m-%d"
 | 
				
			||||||
 | 
					        - options (dict): Options to customize the widget, see README
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    picker_type = 'DATE'
 | 
				
			||||||
 | 
					    format = '%Y-%m-%d'
 | 
				
			||||||
 | 
					    format_key = 'DATE_INPUT_FORMATS'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TimePickerInput(BasePickerInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Widget to display a Time-Picker Calendar on a TimeField property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Args:
 | 
				
			||||||
 | 
					        - attrs (dict): HTML attributes of rendered HTML input
 | 
				
			||||||
 | 
					        - format (string): Python DateTime format eg. "%Y-%m-%d"
 | 
				
			||||||
 | 
					        - options (dict): Options to customize the widget, see README
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    picker_type = 'TIME'
 | 
				
			||||||
 | 
					    format = '%H:%M'
 | 
				
			||||||
 | 
					    format_key = 'TIME_INPUT_FORMATS'
 | 
				
			||||||
 | 
					    template_name = 'bootstrap_datepicker_plus/time_picker.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DateTimePickerInput(BasePickerInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Widget to display a DateTime-Picker Calendar on a DateTimeField property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Args:
 | 
				
			||||||
 | 
					        - attrs (dict): HTML attributes of rendered HTML input
 | 
				
			||||||
 | 
					        - format (string): Python DateTime format eg. "%Y-%m-%d"
 | 
				
			||||||
 | 
					        - options (dict): Options to customize the widget, see README
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    picker_type = 'DATETIME'
 | 
				
			||||||
 | 
					    format = '%Y-%m-%d %H:%M'
 | 
				
			||||||
 | 
					    format_key = 'DATETIME_INPUT_FORMATS'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MonthPickerInput(BasePickerInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Widget to display a Month-Picker Calendar on a DateField property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Args:
 | 
				
			||||||
 | 
					        - attrs (dict): HTML attributes of rendered HTML input
 | 
				
			||||||
 | 
					        - format (string): Python DateTime format eg. "%Y-%m-%d"
 | 
				
			||||||
 | 
					        - options (dict): Options to customize the widget, see README
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    picker_type = 'MONTH'
 | 
				
			||||||
 | 
					    format = '01/%m/%Y'
 | 
				
			||||||
 | 
					    format_key = 'DATE_INPUT_FORMATS'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class YearPickerInput(BasePickerInput):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Widget to display a Year-Picker Calendar on a DateField property.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Args:
 | 
				
			||||||
 | 
					        - attrs (dict): HTML attributes of rendered HTML input
 | 
				
			||||||
 | 
					        - format (string): Python DateTime format eg. "%Y-%m-%d"
 | 
				
			||||||
 | 
					        - options (dict): Options to customize the widget, see README
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    picker_type = 'YEAR'
 | 
				
			||||||
 | 
					    format = '01/01/%Y'
 | 
				
			||||||
 | 
					    format_key = 'DATE_INPUT_FORMATS'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _link_to(self, linked_picker):
 | 
				
			||||||
 | 
					        """Customize the options when linked with other date-time input"""
 | 
				
			||||||
 | 
					        yformat = self.config['options']['format'].replace('-01-01', '-12-31')
 | 
				
			||||||
 | 
					        self.config['options']['format'] = yformat
 | 
				
			||||||
@@ -48,6 +48,7 @@ INSTALLED_APPS = [
 | 
				
			|||||||
    'django.contrib.sites',
 | 
					    'django.contrib.sites',
 | 
				
			||||||
    'django.contrib.messages',
 | 
					    'django.contrib.messages',
 | 
				
			||||||
    'django.contrib.staticfiles',
 | 
					    'django.contrib.staticfiles',
 | 
				
			||||||
 | 
					    'django.forms',
 | 
				
			||||||
    # API
 | 
					    # API
 | 
				
			||||||
    'rest_framework',
 | 
					    'rest_framework',
 | 
				
			||||||
    'rest_framework.authtoken',
 | 
					    'rest_framework.authtoken',
 | 
				
			||||||
@@ -100,6 +101,8 @@ TEMPLATES = [
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WSGI_APPLICATION = 'note_kfet.wsgi.application'
 | 
					WSGI_APPLICATION = 'note_kfet.wsgi.application'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Password validation
 | 
					# Password validation
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										121
									
								
								static/bootstrap_datepicker_plus/css/datepicker-widget.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								static/bootstrap_datepicker_plus/css/datepicker-widget.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					@font-face {
 | 
				
			||||||
 | 
					    font-family: 'Glyphicons Halflings';
 | 
				
			||||||
 | 
					    src: url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.eot');
 | 
				
			||||||
 | 
					    src: url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
 | 
				
			||||||
 | 
					     url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2') format('woff2'),
 | 
				
			||||||
 | 
					     url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff') format('woff'),
 | 
				
			||||||
 | 
					     url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.ttf') format('truetype'),
 | 
				
			||||||
 | 
					     url('//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    top: 1px;
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    font-family: 'Glyphicons Halflings';
 | 
				
			||||||
 | 
					    font-style: normal;
 | 
				
			||||||
 | 
					    font-weight: normal;
 | 
				
			||||||
 | 
					    line-height: 1;
 | 
				
			||||||
 | 
					    -webkit-font-smoothing: antialiased;
 | 
				
			||||||
 | 
					    -moz-osx-font-smoothing: grayscale;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-time:before {
 | 
				
			||||||
 | 
					    content: "\e023";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-chevron-left:before {
 | 
				
			||||||
 | 
					    content: "\e079";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-chevron-right:before {
 | 
				
			||||||
 | 
					    content: "\e080";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-chevron-up:before {
 | 
				
			||||||
 | 
					    content: "\e113";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-chevron-down:before {
 | 
				
			||||||
 | 
					    content: "\e114";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-calendar:before {
 | 
				
			||||||
 | 
					    content: "\e109";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-screenshot:before {
 | 
				
			||||||
 | 
					    content: "\e087";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-trash:before {
 | 
				
			||||||
 | 
					    content: "\e020";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.glyphicon-remove:before {
 | 
				
			||||||
 | 
					    content: "\e014";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .btn {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    padding: 6px 12px;
 | 
				
			||||||
 | 
					    margin-bottom: 0;
 | 
				
			||||||
 | 
					    font-size: 14px;
 | 
				
			||||||
 | 
					    font-weight: normal;
 | 
				
			||||||
 | 
					    line-height: 1.42857143;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    white-space: nowrap;
 | 
				
			||||||
 | 
					    vertical-align: middle;
 | 
				
			||||||
 | 
					    -ms-touch-action: manipulation;
 | 
				
			||||||
 | 
					    touch-action: manipulation;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    -webkit-user-select: none;
 | 
				
			||||||
 | 
					    -moz-user-select: none;
 | 
				
			||||||
 | 
					    -ms-user-select: none;
 | 
				
			||||||
 | 
					    user-select: none;
 | 
				
			||||||
 | 
					    background-image: none;
 | 
				
			||||||
 | 
					    border: 1px solid transparent;
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget.dropdown-menu {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    z-index: 1000;
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					    float: left;
 | 
				
			||||||
 | 
					    min-width: 160px;
 | 
				
			||||||
 | 
					    padding: 5px 0;
 | 
				
			||||||
 | 
					    margin: 2px 0 0;
 | 
				
			||||||
 | 
					    font-size: 14px;
 | 
				
			||||||
 | 
					    text-align: left;
 | 
				
			||||||
 | 
					    list-style: none;
 | 
				
			||||||
 | 
					    background-color: #fff;
 | 
				
			||||||
 | 
					    -webkit-background-clip: padding-box;
 | 
				
			||||||
 | 
					    background-clip: padding-box;
 | 
				
			||||||
 | 
					    border: 1px solid #ccc;
 | 
				
			||||||
 | 
					    border: 1px solid rgba(0, 0, 0, .15);
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
 | 
				
			||||||
 | 
					    box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .list-unstyled {
 | 
				
			||||||
 | 
					    padding-left: 0;
 | 
				
			||||||
 | 
					    list-style: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .collapse {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .collapse.in {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* fix for bootstrap4 */
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .table-condensed > thead > tr > th,
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .table-condensed > tbody > tr > td,
 | 
				
			||||||
 | 
					.bootstrap-datetimepicker-widget .table-condensed > tfoot > tr > td {
 | 
				
			||||||
 | 
					    padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								static/bootstrap_datepicker_plus/js/datepicker-widget.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								static/bootstrap_datepicker_plus/js/datepicker-widget.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					jQuery(function ($) {
 | 
				
			||||||
 | 
					    var datepickerDict = {};
 | 
				
			||||||
 | 
					    var isBootstrap4 = $.fn.collapse.Constructor.VERSION.split('.').shift() == "4";
 | 
				
			||||||
 | 
					    function fixMonthEndDate(e, picker) {
 | 
				
			||||||
 | 
					        e.date && picker.val().length && picker.val(e.date.endOf('month').format('YYYY-MM-DD'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    $("[dp_config]:not([disabled])").each(function (i, element) {
 | 
				
			||||||
 | 
					        var $element = $(element), data = {};
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            data = JSON.parse($element.attr('dp_config'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (x) { }
 | 
				
			||||||
 | 
					        if (data.id && data.options) {
 | 
				
			||||||
 | 
					            data.$element = $element.datetimepicker(data.options);
 | 
				
			||||||
 | 
					            data.datepickerdata = $element.data("DateTimePicker");
 | 
				
			||||||
 | 
					            datepickerDict[data.id] = data;
 | 
				
			||||||
 | 
					            data.$element.next('.input-group-addon').on('click', function(){
 | 
				
			||||||
 | 
					                data.datepickerdata.show();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            if(isBootstrap4){
 | 
				
			||||||
 | 
					                data.$element.on("dp.show", function (e) {
 | 
				
			||||||
 | 
					                    $('.collapse.in').addClass('show');
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    $.each(datepickerDict, function (id, to_picker) {
 | 
				
			||||||
 | 
					        if (to_picker.linked_to) {
 | 
				
			||||||
 | 
					            var from_picker = datepickerDict[to_picker.linked_to];
 | 
				
			||||||
 | 
					            from_picker.datepickerdata.maxDate(to_picker.datepickerdata.date() || false);
 | 
				
			||||||
 | 
					            to_picker.datepickerdata.minDate(from_picker.datepickerdata.date() || false);
 | 
				
			||||||
 | 
					            from_picker.$element.on("dp.change", function (e) {
 | 
				
			||||||
 | 
					                to_picker.datepickerdata.minDate(e.date || false);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            to_picker.$element.on("dp.change", function (e) {
 | 
				
			||||||
 | 
					                if (to_picker.picker_type == 'MONTH') fixMonthEndDate(e, to_picker.$element);
 | 
				
			||||||
 | 
					                from_picker.datepickerdata.maxDate(e.date || false);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            if (to_picker.picker_type == 'MONTH') {
 | 
				
			||||||
 | 
					                to_picker.$element.on("dp.hide", function (e) {
 | 
				
			||||||
 | 
					                    fixMonthEndDate(e, to_picker.$element);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                fixMonthEndDate({ date: to_picker.datepickerdata.date() }, to_picker.$element);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if(isBootstrap4) {
 | 
				
			||||||
 | 
					        $('body').on('show.bs.collapse','.bootstrap-datetimepicker-widget .collapse',function(e){
 | 
				
			||||||
 | 
					            $(e.target).addClass('in');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        $('body').on('hidden.bs.collapse','.bootstrap-datetimepicker-widget .collapse',function(e){
 | 
				
			||||||
 | 
					            $(e.target).removeClass('in');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										6
									
								
								templates/bootstrap_datepicker_plus/date_picker.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								templates/bootstrap_datepicker_plus/date_picker.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<div class="input-group date">
 | 
				
			||||||
 | 
					    {% include "bootstrap_datepicker_plus/input.html" %}
 | 
				
			||||||
 | 
					    <div class="input-group-addon input-group-append" data-target="#datetimepicker1" data-toggle="datetimepickerv">
 | 
				
			||||||
 | 
					        <div class="input-group-text"><i class="glyphicon glyphicon-calendar"></i></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										4
									
								
								templates/bootstrap_datepicker_plus/input.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								templates/bootstrap_datepicker_plus/input.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None and widget.value != "" %}
 | 
				
			||||||
 | 
					       value="{{ widget.value }}"{% endif %}{% for name, value in widget.attrs.items %}{% ifnotequal value False %}
 | 
				
			||||||
 | 
					    {{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}
 | 
				
			||||||
 | 
					{% endifnotequal %}{% endfor %}/>
 | 
				
			||||||
							
								
								
									
										6
									
								
								templates/bootstrap_datepicker_plus/time_picker.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								templates/bootstrap_datepicker_plus/time_picker.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<div class="input-group date">
 | 
				
			||||||
 | 
					    {% include "bootstrap_datepicker_plus/input.html" %}
 | 
				
			||||||
 | 
					    <div class="input-group-addon input-group-append" data-target="#datetimepicker1" data-toggle="datetimepickerv">
 | 
				
			||||||
 | 
					        <div class="input-group-text"><i class="glyphicon glyphicon-time"></i></div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
							
								
								
									
										11
									
								
								templates/note/amount_input.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/note/amount_input.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<div class="input-group">
 | 
				
			||||||
 | 
					    <input class="form-control mx-auto d-block" type="number" min="0" step="0.01"
 | 
				
			||||||
 | 
					           {% if widget.value != None and widget.value != "" %}value="{{ widget.value }}"{% endif %}
 | 
				
			||||||
 | 
					           name="{{ widget.name }}"
 | 
				
			||||||
 | 
					            {% for name, value in widget.attrs.items %}
 | 
				
			||||||
 | 
					                {% ifnotequal value False %}{{ name }}{% ifnotequal value True %}="{{ value|stringformat:'s' }}"{% endifnotequal %}{% endifnotequal %}
 | 
				
			||||||
 | 
					            {% endfor %}>
 | 
				
			||||||
 | 
					    <div class="input-group-append">
 | 
				
			||||||
 | 
					        <span class="input-group-text">€</span>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@@ -126,12 +126,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 | 
				
			|||||||
    <div class="form-row">
 | 
					    <div class="form-row">
 | 
				
			||||||
        <div class="form-group col-md-6">
 | 
					        <div class="form-group col-md-6">
 | 
				
			||||||
            <label for="amount">{% trans "Amount" %} :</label>
 | 
					            <label for="amount">{% trans "Amount" %} :</label>
 | 
				
			||||||
            <div class="input-group">
 | 
					            {% include "note/amount_input.html" with widget=amount_widget %}
 | 
				
			||||||
                <input class="form-control mx-auto d-block" type="number" min="0" step="0.01" id="amount" />
 | 
					 | 
				
			||||||
                <div class="input-group-append">
 | 
					 | 
				
			||||||
                    <span class="input-group-text">€</span>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="form-group col-md-6">
 | 
					        <div class="form-group col-md-6">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
{% extends "base.html" %}
 | 
					{% extends "base.html" %}
 | 
				
			||||||
{% load static %}
 | 
					{% load static %}
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% load crispy_forms_tags pretty_money %}
 | 
					{% load crispy_forms_tags %}
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
    <p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
 | 
					    <p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
 | 
				
			||||||
    <form method="post" action="">
 | 
					    <form method="post" action="">
 | 
				
			||||||
@@ -27,17 +27,7 @@
 | 
				
			|||||||
                <tr class="row-formset">
 | 
					                <tr class="row-formset">
 | 
				
			||||||
                    <td>{{ form.designation }}</td>
 | 
					                    <td>{{ form.designation }}</td>
 | 
				
			||||||
                    <td>{{ form.quantity }}</td>
 | 
					                    <td>{{ form.quantity }}</td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>{{ form.amount }}</td>
 | 
				
			||||||
                        {# Use custom input for amount, with the € symbol #}
 | 
					 | 
				
			||||||
                        <div class="input-group">
 | 
					 | 
				
			||||||
                            <input type="number" name="product_set-{{ forloop.counter0 }}-amount" step="0.01"
 | 
					 | 
				
			||||||
                                   id="id_product_set-{{ forloop.counter0 }}-amount"
 | 
					 | 
				
			||||||
                                   value="{{ form.instance.amount|cents_to_euros }}">
 | 
					 | 
				
			||||||
                            <div class="input-group-append">
 | 
					 | 
				
			||||||
                                <span class="input-group-text">€</span>
 | 
					 | 
				
			||||||
                            </div>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                    </td>
 | 
					 | 
				
			||||||
                    {# These fields are hidden but handled by the formset to link the id and the invoice id #}
 | 
					                    {# These fields are hidden but handled by the formset to link the id and the invoice id #}
 | 
				
			||||||
                    {{ form.invoice }}
 | 
					                    {{ form.invoice }}
 | 
				
			||||||
                    {{ form.id }}
 | 
					                    {{ form.id }}
 | 
				
			||||||
@@ -64,15 +54,7 @@
 | 
				
			|||||||
            <tr class="row-formset">
 | 
					            <tr class="row-formset">
 | 
				
			||||||
                <td>{{ formset.empty_form.designation }}</td>
 | 
					                <td>{{ formset.empty_form.designation }}</td>
 | 
				
			||||||
                <td>{{ formset.empty_form.quantity }} </td>
 | 
					                <td>{{ formset.empty_form.quantity }} </td>
 | 
				
			||||||
                <td>
 | 
					                <td>{{ formset.empty_form.amount }}</td>
 | 
				
			||||||
                    <div class="input-group">
 | 
					 | 
				
			||||||
                        <input type="number" name="product_set-__prefix__-amount" step="0.01"
 | 
					 | 
				
			||||||
                               id="id_product_set-__prefix__-amount">
 | 
					 | 
				
			||||||
                        <div class="input-group-append">
 | 
					 | 
				
			||||||
                            <span class="input-group-text">€</span>
 | 
					 | 
				
			||||||
                        </div>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </td>
 | 
					 | 
				
			||||||
                {{ formset.empty_form.invoice }}
 | 
					                {{ formset.empty_form.invoice }}
 | 
				
			||||||
                {{ formset.empty_form.id }}
 | 
					                {{ formset.empty_form.id }}
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user