Gustavosdo/summum

View on GitHub
estagio/venda/admin.py

Summary

Maintainability
F
3 days
Test Coverage
#-*- coding: UTF-8 -*-
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.conf.urls import url
from django.utils.timezone import utc
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
from django.contrib.admin.models import LogEntry, ADDITION
from django.utils.encoding import force_text
from django.contrib.contenttypes.models import ContentType
from django.contrib import messages
from django.utils.html import format_html
from salmonella.admin import SalmonellaMixin
from import_export.admin import ExportMixin
from daterange_filter.filter import DateRangeFilter
from selectable_filter.filter import SelectableFilter
import pandas as pd

import datetime
import copy

from venda.models import Venda, ItensVenda
from venda.forms import VendaForm, ItensVendaForm, ItensVendaFormSet
from venda.views import get_valor_unitario, get_endereco_entrega_cliente, overview_vendas
from configuracoes.models import Parametrizacao
from venda.export import VendaResource

# class EntregaVendaAdmin(ExportMixin, admin.ModelAdmin):
#     resource_class = EntregaVendaResource
#     model = EntregaVenda
#     actions = None

#     list_display = ('id_venda', 'link_venda', 'endereco', 'data', 'posicao', 'posicao_mapa')
#     search_fields = ['id',]
#     date_hierarchy = 'data'
#     list_filter = (('data', DateRangeFilter),)
#     # readonly_fields = ('data',)

#     def posicao_mapa(self, instance):
#         if instance.posicao is not None:
#             return '<img src="http://maps.googleapis.com/maps/api/staticmap?center=%(latitude)s,%(longitude)s&zoom=%(zoom)s&size=%(width)sx%(height)s&maptype=roadmap&markers=%(latitude)s,%(longitude)s&sensor=false&visual_refresh=true&scale=%(scale)s" width="%(width)s" height="%(height)s">' % {
#                 'latitude': instance.posicao.latitude,
#                 'longitude': instance.posicao.longitude,
#                 'zoom': 15,
#                 'width': 100,
#                 'height': 100,
#                 'scale': 2
#             }
#     posicao_mapa.allow_tags = True
#     posicao_mapa.short_description = _(u"Posição no mapa")


#     def id_venda(object, instance):
        
#         return "<a href=\"/%s/%s/%s/#info_entrega\">%s</a>" % (instance._meta.app_label, instance.venda._meta.model_name, instance.venda, instance.id,)
#     id_venda.allow_tags = True
#     id_venda.short_description = _(u"ID")


#     def link_venda(object, instance):

#         return "<a href=\"/%s/%s/%s/#info_entrega\">%s</a>" % (instance._meta.app_label, instance.venda._meta.model_name, instance.venda, instance.venda,)
#     link_venda.allow_tags = True
#     link_venda.short_description = _(u"Venda")


#     def has_add_permission(self, request, obj=None):
#         return False



# class EntregaVendaInline(admin.StackedInline):
#     form = EntregaVendaForm
#     model = EntregaVenda
#     suit_classes = 'suit-tab suit-tab-info_entrega'
#     fields = ('status', 'endereco', 'data', 'observacao', 'posicao', 'venda')
#     list_display = ('endereco', 'cidade', 'data', 'posicao', 'venda',)

#     fieldsets = (
#                 (None, {
#                         "fields" : ("status",)
#                 }),
#                 ("Detalhes", {
#                         #"classes" : ("collapse",),
#                         "fields" : ("endereco", "data", 'observacao', 'posicao', 'venda')
#                 })
#     )


# class EntregaVendaAddInline(EntregaVendaInline):
#     fieldsets = ((None, {
#                         "fields" : ("status",)
#                 }),)



class ItensVendaInline(SalmonellaMixin, admin.TabularInline):
    form = ItensVendaForm
    formset = ItensVendaFormSet
    model = ItensVenda
    # can_delete = False
    suit_classes = 'suit-tab suit-tab-geral'
    fields = ('produto', 'quantidade', 'valor_unitario', 'desconto', 'valor_total')
    salmonella_fields = ('produto',)
    template = "admin/edit_inline/tabular.html"  # Chama o template personalizado para realizar da inline para fazer todo o tratamento necessário para a tela de vendas


    def get_formset(self, request, obj=None, **kwargs): 
        u""" Altera a quantidade de inlines definida como padrão caso o registro seja salvo no BD """

        if obj: 
            kwargs['extra'] = 0
        else:
            try:
                quantidade = Parametrizacao.objects.get().quantidade_inlines_venda
            except:
                quantidade = 5

            if quantidade:
                kwargs['extra'] = int(quantidade)
            else: 
                kwargs['extra'] = 5

        return super(ItensVendaInline, self).get_formset(request, obj, **kwargs) 


    def get_readonly_fields(self, request, obj=None):
        u""" Define todos os campos da inline como somente leitura caso o registro seja salvo no BD """

        if obj:
            if obj.pedido == 'N' or obj.status or (obj.pedido == 'S' and obj.status_pedido):
                return ['produto', 'quantidade', 'valor_unitario', 'desconto', 'valor_total',]
            return []
        else:
            return []



class VendaAdmin(ExportMixin, SalmonellaMixin, admin.ModelAdmin):
    resource_class = VendaResource
    form = VendaForm
    model = Venda
    actions = None

    list_display = ('id', 'formata_data_venda', 'cliente', 'forma_pagamento', 'total', 'pedido', 'status_pedido', 'status')
    search_fields = ['id', 'cliente']
    date_hierarchy = 'data_venda'
    list_filter = (('cliente', SelectableFilter), ('data_venda', DateRangeFilter), 'forma_pagamento', 'status', 'pedido', 'status_pedido')
    readonly_fields = ('data_venda', 'vendedor', 'vendedor_associado')
    salmonella_fields = ('cliente', 'forma_pagamento', 'grupo_encargo',)
    
    suit_js_includes = [
            'js/inline_venda.js',
    ]

    data = datetime.datetime.utcnow().replace(tzinfo=utc)

    def get_urls(self):
        urls = super(VendaAdmin, self).get_urls()
        my_urls = [
            url(r'^get_valor_unitario/(?P<id>\d+)/$', self.admin_site.admin_view(get_valor_unitario)),
            url(r'^get_endereco_entrega_cliente/(?P<id>\d+)/$', self.admin_site.admin_view(get_endereco_entrega_cliente)),
            url(r'^overview/$', self.admin_site.admin_view(overview_vendas)),
            url(r'^(\d+)/change/copia_novo_pedido/$', self.admin_site.admin_view(self.copia_novo_pedido))
        ]
        return my_urls + urls


    def copia_novo_pedido(self, request, id):
        if not self.has_add_permission(request):
            raise PermissionDenied

        # Checar se existe quantidade suficiente em estoque. Passar uma lista na mensagem de erro abaixo com os itens insuficientes em estoque.
        quant_itens = list(ItensVenda.objects.filter(vendas__pk=id).values('pk', 'quantidade', 'produto__pk', 'produto__nome', 'produto__quantidade'))
        quant_itens = pd.DataFrame(quant_itens).groupby(['produto__pk', 'produto__nome', 'produto__quantidade'], as_index=False).sum().values.tolist()

        list_p_limite = ""
        for l in quant_itens:
            if l[4] > l[2]:
                list_p_limite += "<li>[" + str(l[0]) + "] " + l[1] + " - Contém " + str(l[2]) + " itens em estoque.</li>"

        if list_p_limite:
            messages.add_message(request, messages.ERROR, format_html(_(u"<b>Erro ao copiar registro como novo pedido.</b><br>Os produtos relacionados abaixo não possuem quantidade de itens suficiente em estoque: <ul>" + list_p_limite + "</ul>")))
            return HttpResponseRedirect('..')

        # Copia a venda
        obj = Venda.objects.get(pk=id)
        novo_pedido = copy.copy(obj)
        novo_pedido.id = None
        novo_pedido.data_venda = None
        novo_pedido.data_cancelamento = None
        novo_pedido.status = False
        novo_pedido.pedido = 'S'
        novo_pedido.status_pedido = False
        novo_pedido.observacao = _(u"Copiado originalmente como novo pedido através de registro n° %(venda)s.") % {'venda': id}
        novo_pedido.data_pedido = self.data
        novo_pedido.save()

        # Copia os itens de venda
        itens = ItensVenda.objects.filter(vendas__pk=id)
        for i in itens:
            item_obj = ItensVenda.objects.get(pk=str(i))
            novo_item = copy.copy(item_obj)
            novo_item.id = None
            novo_item.vendas = novo_pedido
            novo_item.save()

        # Registra o log da ação
        LogEntry.objects.log_action(
            user_id         = request.user.pk, 
            content_type_id = ContentType.objects.get_for_model(novo_pedido).pk,
            object_id       = novo_pedido.pk,
            object_repr     = force_text(novo_pedido), 
            action_flag     = ADDITION
        )

        # Constrói a url de retorno
        url = reverse("admin:venda_venda_change", args=[novo_pedido.id])

        return HttpResponseRedirect(url)


    def get_form(self, request, obj=None, **kwargs):
        self.inlines = [ 
            ItensVendaInline,
            #EntregaVendaInline,
        ]

        self.suit_form_tabs = (
            ('geral', _(u"Geral")),
            ('info_adicionais', _(u"Informações adicionais")),
            #('info_entrega', _(u"Informações de Entrega")),
        )
        
        self.fieldsets = (
            (None, {
                'classes': ('suit-tab suit-tab-geral',),
                'fields': ('total', 'desconto', 'status', 'data_cancelamento')
            }),
            (None, {
                'classes': ('suit-tab suit-tab-geral',),
                'fields': ('cliente', 'forma_pagamento', 'grupo_encargo', 'data_venda', 'conta_associada')
            }),
            (None, {
                'classes': ('suit-tab suit-tab-info_adicionais',),
                'fields': ('observacao', 'pedido', 'status_pedido', 'data_pedido', 'vendedor_associado', 'status_apoio')
            }),
        )

        if obj is None:
            self.fieldsets[0][1]['fields'] = tuple(x for x in self.fieldsets[0][1]['fields'] if (x!='status' and x!='data_cancelamento'))
            self.fieldsets[1][1]['fields'] = tuple(x for x in self.fieldsets[1][1]['fields'] if (x!='data_venda' and x!='conta_associada'))
            self.fieldsets[2][1]['fields'] = tuple(x for x in self.fieldsets[2][1]['fields'] if (x!='pedido' and x!='status_pedido' and x!='vendedor' and x!='vendedor_associado'))

        else:
            # insert_into_suit_form_tabs = tuple([('info_entrega', _(u"Informações de entrega"))])
            # self.suit_form_tabs += insert_into_suit_form_tabs

            # sit_entrega = EntregaVenda.objects.filter(venda=obj.pk).exists()
            # if sit_entrega:
            #     self.inlines = self.inlines + [EntregaVendaInline,]
            # else:
            #     self.inlines = self.inlines + [EntregaVendaAddInline,]

            if not obj.status:
                self.fieldsets[0][1]['fields'] = tuple(x for x in self.fieldsets[0][1]['fields'] if (x!='data_cancelamento'))

            if obj.pedido == 'N':
                self.fieldsets[2][1]['fields'] = tuple(x for x in self.fieldsets[2][1]['fields'] if (x!='status_pedido'))

            if obj.pedido == 'S' and not obj.status_pedido:
                self.fieldsets[1][1]['fields'] = tuple(x for x in self.fieldsets[1][1]['fields'] if (x!='data_venda'))

        return super(VendaAdmin, self).get_form(request, obj, **kwargs)


    def has_delete_permission(self, request, obj=None):
        u""" Somente o usuário admin pode deletar uma venda. """
        if request.user.is_superuser:
            return True

        else:
            return False

    
    def get_readonly_fields(self, request, obj=None):
        u""" Define todos os campos da venda como somente leitura caso o registro seja salvo no BD """

        if obj:
            if obj.pedido == 'N' or obj.status or (obj.pedido == 'S' and obj.status_pedido):
                return ['total', 'data_venda', 'data_pedido', 'data_cancelamento', 'desconto', 'cliente', 'forma_pagamento', 'pedido', 'status_pedido', 'grupo_encargo', 'status', 'vendedor', 'vendedor_associado', 'formata_data_venda', 'conta_associada']
            return ['data_venda', 'data_pedido', 'data_cancelamento', 'pedido', 'status_pedido', 'status', 'vendedor', 'vendedor_associado', 'formata_data_venda', 'conta_associada']
        else:
            return ['data_venda', 'data_pedido', 'data_cancelamento', 'pedido', 'status_pedido', 'formata_data_venda', 'conta_associada']


    def response_add(self, request, obj):
        u""" Trata a adição da venda dependendo do botão clicado ao salvá-la 
             Criada em 18/11/2014.
        """

        if '_addpedido' in request.POST:
            obj.pedido = 'S'
            obj.data_pedido = self.data
            obj.save()
            return HttpResponseRedirect("../%s" % (obj.pk))
        else:
            obj.pedido = 'N'
            obj.data_venda = self.data
            obj.save()
            return super(VendaAdmin, self).response_add(request, obj)


    def response_change(self, request, obj):
        u""" Trata a alteração da venda dependendo do botão clicado ao salvá-la 
             Criada em 18/11/2014.
        """

        if '_addconfirmapedido' in request.POST:
            obj.status_pedido = True
            obj.status = False
            obj.data_venda = self.data
            obj.save()
            return HttpResponseRedirect("../%s" % (obj.pk))

        if '_addcancelavenda' in request.POST:
            obj.botao_acionado = '_addcancelavenda'
            obj.data_cancelamento = self.data
            obj.save()
            return HttpResponseRedirect("../%s" % (obj.pk))
        else:
            return super(VendaAdmin, self).response_change(request, obj)


    def suit_row_attributes(self, obj, request):
        rowclass = ''
        if obj.status:
            rowclass = 'error'

        return {'class': rowclass}


    def save_model(self, request, obj, form, change):
        if not obj.pk:
            obj.vendedor = request.user
        
        obj.save()


admin.site.register(Venda, VendaAdmin)
# admin.site.register(EntregaVenda, EntregaVendaAdmin)