Merge pull request 'Generando cuadre del tarro en vuetify' (#83) from streamline_reconciliation_jar_process_#69 into main
Reviewed-on: OneTeam/don_confiao#83
This commit is contained in:
		
							
								
								
									
										29
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								Rakefile
									
									
									
									
									
								
							@@ -10,7 +10,7 @@ namespace :live do
 | 
				
			|||||||
    compose('up', '--build', '-d', compose: DOCKER_COMPOSE)
 | 
					    compose('up', '--build', '-d', compose: DOCKER_COMPOSE)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   desc 'monitorear salida'
 | 
					  desc 'monitorear salida'
 | 
				
			||||||
  task :tail do
 | 
					  task :tail do
 | 
				
			||||||
    compose('logs', '-f', 'django', compose: DOCKER_COMPOSE)
 | 
					    compose('logs', '-f', 'django', compose: DOCKER_COMPOSE)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -20,7 +20,12 @@ namespace :live do
 | 
				
			|||||||
    compose('logs', '-f', '-n 50', 'django', compose: DOCKER_COMPOSE)
 | 
					    compose('logs', '-f', '-n 50', 'django', compose: DOCKER_COMPOSE)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  desc 'detener entorno'
 | 
					  desc 'iniciar entorno'
 | 
				
			||||||
 | 
					  task :start do
 | 
				
			||||||
 | 
					    compose('start', compose: DOCKER_COMPOSE)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  desc 'bajar entorno'
 | 
				
			||||||
  task :down do
 | 
					  task :down do
 | 
				
			||||||
    compose('down', compose: DOCKER_COMPOSE)
 | 
					    compose('down', compose: DOCKER_COMPOSE)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -52,6 +57,26 @@ namespace :live do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					desc 'Desarrollo'
 | 
				
			||||||
 | 
					namespace :dev do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  desc 'correr test de django'
 | 
				
			||||||
 | 
					  task :test do
 | 
				
			||||||
 | 
					    compose('exec', 'django', 'python', '/app/manage.py', 'test', '/app/don_confiao')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  desc 'crear migraciones'
 | 
				
			||||||
 | 
					  task :makemigrations do
 | 
				
			||||||
 | 
					    compose('exec', 'django', 'python', '/app/manage.py', 'makemigrations')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  desc 'aplicar migraciones'
 | 
				
			||||||
 | 
					  task :migrate do
 | 
				
			||||||
 | 
					    compose('exec', 'django', 'python', '/app/manage.py', 'migrate')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def compose(*arg, compose: DOCKER_COMPOSE)
 | 
					def compose(*arg, compose: DOCKER_COMPOSE)
 | 
				
			||||||
  sh "docker compose -f #{compose} #{arg.join(' ')}"
 | 
					  sh "docker compose -f #{compose} #{arg.join(' ')}"
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,13 @@
 | 
				
			|||||||
from rest_framework import viewsets
 | 
					from rest_framework import viewsets
 | 
				
			||||||
from rest_framework.response import Response
 | 
					from rest_framework.response import Response
 | 
				
			||||||
 | 
					from rest_framework.status import HTTP_400_BAD_REQUEST
 | 
				
			||||||
 | 
					from rest_framework.views import APIView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Sale, SaleLine, Customer, Product
 | 
					from .models import Sale, SaleLine, Customer, Product, ReconciliationJar
 | 
				
			||||||
from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer
 | 
					from .serializers import SaleSerializer, ProductSerializer, CustomerSerializer, ReconciliationJarSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from decimal import Decimal
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SaleView(viewsets.ModelViewSet):
 | 
					class SaleView(viewsets.ModelViewSet):
 | 
				
			||||||
    queryset = Sale.objects.all()
 | 
					    queryset = Sale.objects.all()
 | 
				
			||||||
@@ -46,3 +50,53 @@ class ProductView(viewsets.ModelViewSet):
 | 
				
			|||||||
class CustomerView(viewsets.ModelViewSet):
 | 
					class CustomerView(viewsets.ModelViewSet):
 | 
				
			||||||
    queryset = Customer.objects.all()
 | 
					    queryset = Customer.objects.all()
 | 
				
			||||||
    serializer_class = CustomerSerializer
 | 
					    serializer_class = CustomerSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReconciliateJarView(APIView):
 | 
				
			||||||
 | 
					    def post(self, request):
 | 
				
			||||||
 | 
					        data = request.data
 | 
				
			||||||
 | 
					        cash_purchases_id = data.get('cash_purchases')
 | 
				
			||||||
 | 
					        serializer = ReconciliationJarSerializer(data=data)
 | 
				
			||||||
 | 
					        if serializer.is_valid():
 | 
				
			||||||
 | 
					            cash_purchases = Sale.objects.filter(pk__in=cash_purchases_id)
 | 
				
			||||||
 | 
					            if not self._is_valid_total(cash_purchases, data.get('total_cash_purchases')):
 | 
				
			||||||
 | 
					                return Response(
 | 
				
			||||||
 | 
					                    {'error': 'total_cash_purchases not equal to sum of all purchases.'},
 | 
				
			||||||
 | 
					                    status=HTTP_400_BAD_REQUEST
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            reconciliation = serializer.save()
 | 
				
			||||||
 | 
					            other_purchases = self._get_other_purchases(data.get('other_totals'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self._link_purchases(reconciliation, cash_purchases, other_purchases)
 | 
				
			||||||
 | 
					            return Response({'id': reconciliation.id})
 | 
				
			||||||
 | 
					        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request):
 | 
				
			||||||
 | 
					        reconciliations = ReconciliationJar.objects.all()
 | 
				
			||||||
 | 
					        serializer = ReconciliationJarSerializer(reconciliations, many=True)
 | 
				
			||||||
 | 
					        return Response(serializer.data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _is_valid_total(self, purchases, total):
 | 
				
			||||||
 | 
					        calculated_total = sum(p.get_total() for p in purchases)
 | 
				
			||||||
 | 
					        return calculated_total == Decimal(total)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_other_purchases(self, other_totals):
 | 
				
			||||||
 | 
					        if not other_totals:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        purchases = []
 | 
				
			||||||
 | 
					        for method in other_totals:
 | 
				
			||||||
 | 
					            purchases.extend(other_totals[method]['purchases'])
 | 
				
			||||||
 | 
					        if purchases:
 | 
				
			||||||
 | 
					            return Sale.objects.filter(pk__in=purchases)
 | 
				
			||||||
 | 
					        return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _link_purchases(self, reconciliation, cash_purchases, other_purchases):
 | 
				
			||||||
 | 
					        for purchase in cash_purchases:
 | 
				
			||||||
 | 
					            purchase.reconciliation = reconciliation
 | 
				
			||||||
 | 
					            purchase.clean()
 | 
				
			||||||
 | 
					            purchase.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for purchase in other_purchases:
 | 
				
			||||||
 | 
					            purchase.reconciliation = reconciliation
 | 
				
			||||||
 | 
					            purchase.clean()
 | 
				
			||||||
 | 
					            purchase.save()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ from django.forms.models import inlineformset_factory
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from django.forms.widgets import DateInput, DateTimeInput
 | 
					from django.forms.widgets import DateInput, DateTimeInput
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Sale, SaleLine, ReconciliationJar, PaymentMethods
 | 
					from .models import Sale, SaleLine, PaymentMethods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
readonly_number_widget = forms.NumberInput(attrs={'readonly': 'readonly'})
 | 
					readonly_number_widget = forms.NumberInput(attrs={'readonly': 'readonly'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,18 +64,3 @@ SaleLineFormSet = inlineformset_factory(
 | 
				
			|||||||
    extra=1,
 | 
					    extra=1,
 | 
				
			||||||
    fields='__all__'
 | 
					    fields='__all__'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ReconciliationJarForm(forms.ModelForm):
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = ReconciliationJar
 | 
					 | 
				
			||||||
        fields = [
 | 
					 | 
				
			||||||
            'date_time',
 | 
					 | 
				
			||||||
            'description',
 | 
					 | 
				
			||||||
            'reconcilier',
 | 
					 | 
				
			||||||
            'cash_taken',
 | 
					 | 
				
			||||||
            'cash_discrepancy',
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
        widgets = {
 | 
					 | 
				
			||||||
            'date_time': DateTimeInput(attrs={'type': 'datetime-local'})
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <span>{{ formattedValue }}</span>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					  export default {
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      value: {
 | 
				
			||||||
 | 
					        type: Number,
 | 
				
			||||||
 | 
					        required: true
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      locale: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        default: 'es-CO',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      currency: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        default: 'COP',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computed: {
 | 
				
			||||||
 | 
					      formattedValue() {
 | 
				
			||||||
 | 
					        return new Intl.NumberFormat(this.locale, { style: 'currency', currency: this.currency }).format(this.value);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
         menuItems: [
 | 
					         menuItems: [
 | 
				
			||||||
             { title: 'Inicio', route: '/'},
 | 
					             { title: 'Inicio', route: '/'},
 | 
				
			||||||
             { title: 'Comprar', route:'/comprar'},
 | 
					             { title: 'Comprar', route:'/comprar'},
 | 
				
			||||||
 | 
					             { title: 'Cuadrar tarro', route: '/cuadrar_tarro'}
 | 
				
			||||||
         ],
 | 
					         ],
 | 
				
			||||||
     }),
 | 
					     }),
 | 
				
			||||||
     watch: {
 | 
					     watch: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,213 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <v-container>
 | 
				
			||||||
 | 
					    <v-toolbar>
 | 
				
			||||||
 | 
					      <v-toolbar-title> Cuadre del Tarro </v-toolbar-title>
 | 
				
			||||||
 | 
					    </v-toolbar>
 | 
				
			||||||
 | 
					    <v-card>
 | 
				
			||||||
 | 
					      <v-card-text>
 | 
				
			||||||
 | 
					        <v-form ref="taker" v-model="valid">
 | 
				
			||||||
 | 
					          <v-text-field
 | 
				
			||||||
 | 
					            v-model="reconciliation.date_time"
 | 
				
			||||||
 | 
					            label="Fecha"
 | 
				
			||||||
 | 
					            type="datetime-local"
 | 
				
			||||||
 | 
					            :rules="[rules.required]"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					            readonly
 | 
				
			||||||
 | 
					          ></v-text-field>
 | 
				
			||||||
 | 
					        <v-text-field
 | 
				
			||||||
 | 
					          v-model="reconciliation.reconcilier"
 | 
				
			||||||
 | 
					          label="Cajero"
 | 
				
			||||||
 | 
					          :rules="[rules.required]"
 | 
				
			||||||
 | 
					          required
 | 
				
			||||||
 | 
					        ></v-text-field>
 | 
				
			||||||
 | 
					        <v-text-field
 | 
				
			||||||
 | 
					          v-model="reconciliation.total_cash_purchases"
 | 
				
			||||||
 | 
					          label="Total Ventas en efectivo"
 | 
				
			||||||
 | 
					          :rules="[rules.required]"
 | 
				
			||||||
 | 
					          prefix="$"
 | 
				
			||||||
 | 
					          type="number"
 | 
				
			||||||
 | 
					          readonly
 | 
				
			||||||
 | 
					        ></v-text-field>
 | 
				
			||||||
 | 
					        <v-text-field
 | 
				
			||||||
 | 
					          v-model="reconciliation.cash_taken"
 | 
				
			||||||
 | 
					          label="Dinero Recogido"
 | 
				
			||||||
 | 
					          :rules="[rules.required]"
 | 
				
			||||||
 | 
					          prefix="$"
 | 
				
			||||||
 | 
					          type="number"
 | 
				
			||||||
 | 
					        ></v-text-field>
 | 
				
			||||||
 | 
					        <v-text-field
 | 
				
			||||||
 | 
					          v-model="reconciliation.cash_discrepancy"
 | 
				
			||||||
 | 
					          label="Descuadre"
 | 
				
			||||||
 | 
					          :rules="[rules.integer]"
 | 
				
			||||||
 | 
					          prefix="$"
 | 
				
			||||||
 | 
					          type="number"
 | 
				
			||||||
 | 
					        ></v-text-field>
 | 
				
			||||||
 | 
					        <v-btn @click="submit" color="green">Recoger Dinero</v-btn>
 | 
				
			||||||
 | 
					        </v-form>
 | 
				
			||||||
 | 
					      </v-card-text>
 | 
				
			||||||
 | 
					    </v-card>
 | 
				
			||||||
 | 
					    <v-tabs v-model="selectedTab">
 | 
				
			||||||
 | 
					      <v-tab
 | 
				
			||||||
 | 
					        v-for="(purchases, payment_method) in summary.purchases"
 | 
				
			||||||
 | 
					        :key="payment_method"
 | 
				
			||||||
 | 
					        :value="payment_method"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {{ payment_method }}  <CurrencyText :value="totalByMethod(payment_method)"</CurrencyText>
 | 
				
			||||||
 | 
					      </v-tab>
 | 
				
			||||||
 | 
					    </v-tabs>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-tabs-window v-model="selectedTab">
 | 
				
			||||||
 | 
					      <v-card>
 | 
				
			||||||
 | 
					        <v-card-text>
 | 
				
			||||||
 | 
					          <v-tabs-window-item
 | 
				
			||||||
 | 
					            v-for="(purchases, payment_method) in summary.purchases"
 | 
				
			||||||
 | 
					            :key="payment_method"
 | 
				
			||||||
 | 
					            :value="payment_method"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <v-data-table-virtual
 | 
				
			||||||
 | 
					              :headers="summary.headers"
 | 
				
			||||||
 | 
					              :items="summary.purchases[payment_method]"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <template v-slot:item.id="{ item }">
 | 
				
			||||||
 | 
					                <v-btn @click="openSummaryModal(item.id)">{{ item.id }}</v-btn>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					              <template v-slot:item.total="{ item }">
 | 
				
			||||||
 | 
					                <CurrencyText :value="parseFloat(item.total)"></CurrencyText>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					            </v-data-table-virtual>
 | 
				
			||||||
 | 
					          </v-tabs-window-item>
 | 
				
			||||||
 | 
					          <SummaryPurchaseModal :id="selectedPurchaseId" ref="summaryModal" />
 | 
				
			||||||
 | 
					        </v-card-text>
 | 
				
			||||||
 | 
					      </v-card>
 | 
				
			||||||
 | 
					    </v-tabs-window>
 | 
				
			||||||
 | 
					  </v-container>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					  import CurrencyText from './CurrencyText.vue';
 | 
				
			||||||
 | 
					  import SummaryPurchaseModal from './SummaryPurchaseModal.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export default {
 | 
				
			||||||
 | 
					    name: 'ReconciliationJar',
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      msg: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					      SummaryPurchaseModal,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    data () {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        valid: null,
 | 
				
			||||||
 | 
					        selectedPurchaseId: null,
 | 
				
			||||||
 | 
					        selectedTab: 'CASH',
 | 
				
			||||||
 | 
					        reconciliation: {
 | 
				
			||||||
 | 
					          date_time: '',
 | 
				
			||||||
 | 
					          total_cash_purchases: 0,
 | 
				
			||||||
 | 
					          cash_taken: 0,
 | 
				
			||||||
 | 
					          cash_discrepancy: 0,
 | 
				
			||||||
 | 
					          other_totals: {
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          cash_purchases: [],
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        summary: {
 | 
				
			||||||
 | 
					          headers: [
 | 
				
			||||||
 | 
					            {title: 'Id', value: 'id'},
 | 
				
			||||||
 | 
					            {title: 'Fecha', value: 'date'},
 | 
				
			||||||
 | 
					            {title: 'Cliente', value: 'customer.name'},
 | 
				
			||||||
 | 
					            {title: 'Total', value: 'total'},
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          purchases: {},
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        rules: {
 | 
				
			||||||
 | 
					          required: value => !!value || 'Requerido.',
 | 
				
			||||||
 | 
					          integer: value => !!value || value === 0 || 'Requerido.',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    mounted() {
 | 
				
			||||||
 | 
					      this.fetchPurchases();
 | 
				
			||||||
 | 
					      this.reconciliation.date_time = this.getCurrentDate();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					      'reconciliation.cash_taken'() {
 | 
				
			||||||
 | 
					        this.updateDiscrepancy();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					      totalByMethod(method) {
 | 
				
			||||||
 | 
					        if (method in this.summary.purchases) {
 | 
				
			||||||
 | 
					          return this.summary.purchases[method].reduce((a, b) => a + parseFloat(b.total), 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      idsBymethod(method) {
 | 
				
			||||||
 | 
					        if (method in this.summary.purchases) {
 | 
				
			||||||
 | 
					          return this.summary.purchases[method].map(purchase => purchase.id)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return [];
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      processOtherMethods() {
 | 
				
			||||||
 | 
					        for (const method of Object.keys(this.summary.purchases)) {
 | 
				
			||||||
 | 
					          if (method !== 'CASH') {
 | 
				
			||||||
 | 
					            this.reconciliation.other_totals[method] = {
 | 
				
			||||||
 | 
					              total: this.totalByMethod(method),
 | 
				
			||||||
 | 
					              purchases: this.idsBymethod(method),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      updateDiscrepancy() {
 | 
				
			||||||
 | 
					        this.reconciliation.cash_discrepancy = (this.reconciliation.total_cash_purchases || 0 ) - (this.reconciliation.cash_taken || 0);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getCurrentDate() {
 | 
				
			||||||
 | 
					        const today = new Date();
 | 
				
			||||||
 | 
					        const gmtOffSet = -5;
 | 
				
			||||||
 | 
					        const localDate = new Date(today.getTime() + (gmtOffSet * 60 * 60 * 1000));
 | 
				
			||||||
 | 
					        // Formatear la fecha y hora en el formato YYYY-MM-DDTHH:MM
 | 
				
			||||||
 | 
					        const formattedDate = localDate.toISOString().slice(0,16);
 | 
				
			||||||
 | 
					        return formattedDate;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      openSummaryModal(id) {
 | 
				
			||||||
 | 
					        this.selectedPurchaseId = id;
 | 
				
			||||||
 | 
					        this.$refs.summaryModal.dialog = true;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      fetchPurchases() {
 | 
				
			||||||
 | 
					        const endpoint = '/don_confiao/purchases/for_reconciliation';
 | 
				
			||||||
 | 
					        fetch(endpoint)
 | 
				
			||||||
 | 
					          .then(response => response.json())
 | 
				
			||||||
 | 
					          .then(data => {
 | 
				
			||||||
 | 
					            this.summary.purchases = data;
 | 
				
			||||||
 | 
					            this.reconciliation.cash_purchases = this.idsBymethod('CASH');
 | 
				
			||||||
 | 
					            this.reconciliation.total_cash_purchases = this.totalByMethod('CASH');
 | 
				
			||||||
 | 
					            this.processOtherMethods();
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(error => {
 | 
				
			||||||
 | 
					            console.error(error);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      async submit() {
 | 
				
			||||||
 | 
					        this.$refs.taker.validate();
 | 
				
			||||||
 | 
					        if (this.valid) {
 | 
				
			||||||
 | 
					          try {
 | 
				
			||||||
 | 
					            const response = await fetch('/don_confiao/reconciliate_jar', {
 | 
				
			||||||
 | 
					              method: 'POST',
 | 
				
			||||||
 | 
					              headers: {
 | 
				
			||||||
 | 
					                'Content-Type': 'application/json'
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              body: JSON.stringify(this.reconciliation),
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            if (response.ok) {
 | 
				
			||||||
 | 
					              const data = await response.json();
 | 
				
			||||||
 | 
					              console.log('Cuadre enviado:', data);
 | 
				
			||||||
 | 
					              this.$router.push({path: "/"});
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              console.error('Error al enviar el cuadre', response.statusText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          } catch (error) {
 | 
				
			||||||
 | 
					            console.error('Error de red:', error);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <v-dialog v-model="dialog" max-width="400">
 | 
				
			||||||
 | 
					    <v-card>
 | 
				
			||||||
 | 
					      <v-card-text>
 | 
				
			||||||
 | 
					        <SummaryPurchase :id="id"/>
 | 
				
			||||||
 | 
					      </v-card-text>
 | 
				
			||||||
 | 
					      <v-card-actions>
 | 
				
			||||||
 | 
					        <v-spacer></v-spacer>
 | 
				
			||||||
 | 
					        <v-btn text @click="dialog = false">Cerrar</v-btn>
 | 
				
			||||||
 | 
					      </v-card-actions>
 | 
				
			||||||
 | 
					    </v-card>
 | 
				
			||||||
 | 
					  </v-dialog>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					  export default {
 | 
				
			||||||
 | 
					    name: 'SummaryPurchase Modal',
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      id: {
 | 
				
			||||||
 | 
					        type: Number,
 | 
				
			||||||
 | 
					        required: true,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    data() {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        dialog: false,
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <ReconciliationJar />
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script setup>
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.0.6 on 2024-11-18 03:16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('don_confiao', '0033_sale_payment_method'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='sale',
 | 
				
			||||||
 | 
					            name='reconciliation',
 | 
				
			||||||
 | 
					            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.RESTRICT, related_name='Sales', to='don_confiao.reconciliationjar'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='payment',
 | 
				
			||||||
 | 
					            name='type_payment',
 | 
				
			||||||
 | 
					            field=models.CharField(choices=[('CASH', 'Efectivo'), ('CONFIAR', 'Confiar'), ('BANCOLOMBIA', 'Bancolombia')], default='CASH', max_length=30),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name='sale',
 | 
				
			||||||
 | 
					            name='payment_method',
 | 
				
			||||||
 | 
					            field=models.CharField(choices=[('CASH', 'Efectivo'), ('CONFIAR', 'Confiar'), ('BANCOLOMBIA', 'Bancolombia')], default='CASH', max_length=30),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.0.6 on 2024-12-03 02:55
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('don_confiao', '0034_sale_reconciliation_alter_payment_type_payment_and_more'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='reconciliationjar',
 | 
				
			||||||
 | 
					            name='total_cash_purchases',
 | 
				
			||||||
 | 
					            field=models.DecimalField(decimal_places=2, default=0, max_digits=9),
 | 
				
			||||||
 | 
					            preserve_default=False,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					# Generated by Django 5.0.6 on 2024-12-28 22:12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('don_confiao', '0034_alter_payment_type_payment_alter_sale_date_and_more'),
 | 
				
			||||||
 | 
					        ('don_confiao', '0035_reconciliationjar_total_cash_purchases'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -62,6 +62,31 @@ class Product(models.Model):
 | 
				
			|||||||
        return products_list
 | 
					        return products_list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReconciliationJar(models.Model):
 | 
				
			||||||
 | 
					    is_valid = models.BooleanField(default=False)
 | 
				
			||||||
 | 
					    date_time = models.DateTimeField()
 | 
				
			||||||
 | 
					    description = models.CharField(max_length=255, null=True, blank=True)
 | 
				
			||||||
 | 
					    reconcilier = models.CharField(max_length=255, null=False, blank=False)
 | 
				
			||||||
 | 
					    cash_taken = models.DecimalField(max_digits=9, decimal_places=2)
 | 
				
			||||||
 | 
					    cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2)
 | 
				
			||||||
 | 
					    total_cash_purchases = models.DecimalField(max_digits=9, decimal_places=2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clean(self):
 | 
				
			||||||
 | 
					        self._validate_taken_ammount()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_payments(self, payments):
 | 
				
			||||||
 | 
					        for payment in payments:
 | 
				
			||||||
 | 
					            self.payment_set.add(payment)
 | 
				
			||||||
 | 
					        self.is_valid = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate_taken_ammount(self):
 | 
				
			||||||
 | 
					        ammount_cash = self.cash_taken + self.cash_discrepancy
 | 
				
			||||||
 | 
					        if not self.total_cash_purchases == ammount_cash:
 | 
				
			||||||
 | 
					            raise ValidationError(
 | 
				
			||||||
 | 
					                {"cash_taken": _("The taken ammount has discrepancy.")}
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Sale(models.Model):
 | 
					class Sale(models.Model):
 | 
				
			||||||
    customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
 | 
					    customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
 | 
				
			||||||
    date = models.DateTimeField("Date")
 | 
					    date = models.DateTimeField("Date")
 | 
				
			||||||
@@ -74,6 +99,12 @@ class Sale(models.Model):
 | 
				
			|||||||
        blank=False,
 | 
					        blank=False,
 | 
				
			||||||
        null=False
 | 
					        null=False
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    reconciliation = models.ForeignKey(
 | 
				
			||||||
 | 
					        ReconciliationJar,
 | 
				
			||||||
 | 
					        on_delete=models.RESTRICT,
 | 
				
			||||||
 | 
					        related_name='Sales',
 | 
				
			||||||
 | 
					        null=True
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        return f"{self.date} {self.customer}"
 | 
					        return f"{self.date} {self.customer}"
 | 
				
			||||||
@@ -122,38 +153,6 @@ class ReconciliationJarSummary():
 | 
				
			|||||||
        return self._payments
 | 
					        return self._payments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReconciliationJar(models.Model):
 | 
					 | 
				
			||||||
    is_valid = models.BooleanField(default=False)
 | 
					 | 
				
			||||||
    date_time = models.DateTimeField()
 | 
					 | 
				
			||||||
    description = models.CharField(max_length=255, null=True, blank=True)
 | 
					 | 
				
			||||||
    reconcilier = models.CharField(max_length=255, null=False, blank=False)
 | 
					 | 
				
			||||||
    cash_taken = models.DecimalField(max_digits=9, decimal_places=2)
 | 
					 | 
				
			||||||
    cash_discrepancy = models.DecimalField(max_digits=9, decimal_places=2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def clean(self):
 | 
					 | 
				
			||||||
        if not self.is_valid:
 | 
					 | 
				
			||||||
            payments = Payment.get_reconciliation_jar_summary().payments
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            payments = self.payment_set.all()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        payments_amount = Decimal(sum([p.amount for p in payments]))
 | 
					 | 
				
			||||||
        reconciliation_ammount = Decimal(sum([
 | 
					 | 
				
			||||||
            self.cash_taken,
 | 
					 | 
				
			||||||
            self.cash_discrepancy,
 | 
					 | 
				
			||||||
        ]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        equal_ammounts = reconciliation_ammount.compare(payments_amount) == Decimal('0')
 | 
					 | 
				
			||||||
        if not equal_ammounts:
 | 
					 | 
				
			||||||
            raise ValidationError(
 | 
					 | 
				
			||||||
                {"cash_taken": _("The taken ammount has discrepancy.")}
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def add_payments(self, payments):
 | 
					 | 
				
			||||||
        for payment in payments:
 | 
					 | 
				
			||||||
            self.payment_set.add(payment)
 | 
					 | 
				
			||||||
        self.is_valid = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Payment(models.Model):
 | 
					class Payment(models.Model):
 | 
				
			||||||
    date_time = models.DateTimeField()
 | 
					    date_time = models.DateTimeField()
 | 
				
			||||||
    type_payment = models.CharField(
 | 
					    type_payment = models.CharField(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Sale, SaleLine, Product, Customer
 | 
					from .models import Sale, SaleLine, Product, Customer, ReconciliationJar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SaleLineSerializer(serializers.ModelSerializer):
 | 
					class SaleLineSerializer(serializers.ModelSerializer):
 | 
				
			||||||
@@ -20,7 +20,21 @@ class ProductSerializer(serializers.ModelSerializer):
 | 
				
			|||||||
        model = Product
 | 
					        model = Product
 | 
				
			||||||
        fields = ['id', 'name', 'price', 'measuring_unit', 'categories']
 | 
					        fields = ['id', 'name', 'price', 'measuring_unit', 'categories']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CustomerSerializer(serializers.ModelSerializer):
 | 
					class CustomerSerializer(serializers.ModelSerializer):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Customer
 | 
					        model = Customer
 | 
				
			||||||
        fields = ['id', 'name', 'address', 'email', 'phone']
 | 
					        fields = ['id', 'name', 'address', 'email', 'phone']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReconciliationJarSerializer(serializers.ModelSerializer):
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        model = ReconciliationJar
 | 
				
			||||||
 | 
					        fields = [
 | 
				
			||||||
 | 
					            'id',
 | 
				
			||||||
 | 
					            'date_time',
 | 
				
			||||||
 | 
					            'reconcilier',
 | 
				
			||||||
 | 
					            'cash_taken',
 | 
				
			||||||
 | 
					            'cash_discrepancy',
 | 
				
			||||||
 | 
					            'total_cash_purchases',
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@
 | 
				
			|||||||
            <li><a href='/don_confiao/lista_productos'>Productos</a></li>
 | 
					            <li><a href='/don_confiao/lista_productos'>Productos</a></li>
 | 
				
			||||||
            <li><a href='/don_confiao/importar_productos'>Importar Productos</a></li>
 | 
					            <li><a href='/don_confiao/importar_productos'>Importar Productos</a></li>
 | 
				
			||||||
            <li><a href='/don_confiao/importar_terceros'>Importar Terceros</a></li>
 | 
					            <li><a href='/don_confiao/importar_terceros'>Importar Terceros</a></li>
 | 
				
			||||||
            <li><a href='/don_confiao/cuadrar_tarro'>Cuadrar tarro</a></li>
 | 
					 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
    </nav>
 | 
					    </nav>
 | 
				
			||||||
    <p id="page_title" class="text-center decoration-solid  font-mono font-bold text-lg page_title">Don Confiao - Tienda la Ilusión</p>
 | 
					    <p id="page_title" class="text-center decoration-solid  font-mono font-bold text-lg page_title">Don Confiao - Tienda la Ilusión</p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
{% extends 'don_confiao/base.html' %}
 | 
					 | 
				
			||||||
{% block content %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% if summary.total %}
 | 
					 | 
				
			||||||
<div class="reconciliate_jar summary" style="border: solid 1px brown; margin: 10px">
 | 
					 | 
				
			||||||
    <h2>Pagos No reconciliados</h2>
 | 
					 | 
				
			||||||
    <table style="border: solid 1px blue; margin: 10px">
 | 
					 | 
				
			||||||
        <thead>
 | 
					 | 
				
			||||||
            <tr><th>Fecha</th><th>Monto</th></tr>
 | 
					 | 
				
			||||||
        </thead>
 | 
					 | 
				
			||||||
        <tbody>
 | 
					 | 
				
			||||||
            {% for payment in summary.payments %}
 | 
					 | 
				
			||||||
            <tr><td>{{ payment.date_time }}</td><td>{{ payment.amount }}</td></tr>
 | 
					 | 
				
			||||||
            {% endfor %}
 | 
					 | 
				
			||||||
        </tbody>
 | 
					 | 
				
			||||||
        <tfoot>
 | 
					 | 
				
			||||||
            <tr><th>Total</th><td>{{ summary.total }}</td></tr>
 | 
					 | 
				
			||||||
        </tfoot>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<form method="POST">
 | 
					 | 
				
			||||||
    <table style="border: solid 1px blue; margin: 10px">
 | 
					 | 
				
			||||||
        {% csrf_token %}
 | 
					 | 
				
			||||||
        {{ form.as_table }}
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
    <br/><button name="form" type="submit" >Recoger dinero</button>
 | 
					 | 
				
			||||||
</form>
 | 
					 | 
				
			||||||
{% else %}
 | 
					 | 
				
			||||||
<div class="reconciliate_jar information noform">
 | 
					 | 
				
			||||||
    <h2>No hay pagos registrados.</h2>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
from django.test import TestCase
 | 
					 | 
				
			||||||
from django.core.exceptions import ValidationError
 | 
					 | 
				
			||||||
from ..models import Payment, ReconciliationJar
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestBilling(TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_reconciliation_jar_summary(self):
 | 
					 | 
				
			||||||
        cash_payment1, cash_payment2 = self._create_two_cash_payments()
 | 
					 | 
				
			||||||
        jar_summary = Payment.get_reconciliation_jar_summary()
 | 
					 | 
				
			||||||
        self.assertEqual(164000, jar_summary.total)
 | 
					 | 
				
			||||||
        self.assertSetEqual(
 | 
					 | 
				
			||||||
            {cash_payment1, cash_payment2},
 | 
					 | 
				
			||||||
            set(jar_summary.payments)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_reconciliation_jar_summary_use_only_cash(self):
 | 
					 | 
				
			||||||
        cash_payment1, cash_payment2 = self._create_two_cash_payments()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        confiar_payment = Payment()
 | 
					 | 
				
			||||||
        confiar_payment.date_time = '2024-07-07 16:00:00'
 | 
					 | 
				
			||||||
        confiar_payment.type_payment = 'CONFIAR'
 | 
					 | 
				
			||||||
        confiar_payment.amount = 85000
 | 
					 | 
				
			||||||
        confiar_payment.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bancolombia_payment = Payment()
 | 
					 | 
				
			||||||
        bancolombia_payment.date_time = '2024-07-07 12:30:00'
 | 
					 | 
				
			||||||
        bancolombia_payment.type_payment = 'BANCOLOMBIA'
 | 
					 | 
				
			||||||
        bancolombia_payment.amount = 12000
 | 
					 | 
				
			||||||
        bancolombia_payment.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        jar_summary = Payment.get_reconciliation_jar_summary()
 | 
					 | 
				
			||||||
        self.assertEqual(164000, jar_summary.total)
 | 
					 | 
				
			||||||
        self.assertSetEqual(
 | 
					 | 
				
			||||||
            {cash_payment1, cash_payment2},
 | 
					 | 
				
			||||||
            set(jar_summary.payments)
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_fail_validate_reconciliation_jar_with_discrepancy_values(self):
 | 
					 | 
				
			||||||
        cash_payment1, cash_payment2 = self._create_two_cash_payments()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        jar_summary = Payment.get_reconciliation_jar_summary()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        reconciliation_jar = ReconciliationJar()
 | 
					 | 
				
			||||||
        reconciliation_jar.date_time = '2024-07-13 13:02:00'
 | 
					 | 
				
			||||||
        reconciliation_jar.description = "test reconcialiation jar"
 | 
					 | 
				
			||||||
        reconciliation_jar.reconcilier = 'Jorge'
 | 
					 | 
				
			||||||
        reconciliation_jar.cash_float = 0
 | 
					 | 
				
			||||||
        reconciliation_jar.cash_taken = 0
 | 
					 | 
				
			||||||
        reconciliation_jar.cash_discrepancy = 0
 | 
					 | 
				
			||||||
        reconciliation_jar.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        reconciliation_jar.add_payments(jar_summary.payments)
 | 
					 | 
				
			||||||
        with self.assertRaises(ValidationError):
 | 
					 | 
				
			||||||
            reconciliation_jar.clean()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_validate_reconciliation_jar_with_cash_float(self):
 | 
					 | 
				
			||||||
        cash_payment1, cash_payment2 = self._create_two_cash_payments()
 | 
					 | 
				
			||||||
        jar_summary = Payment.get_reconciliation_jar_summary()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        reconciliation_jar = ReconciliationJar()
 | 
					 | 
				
			||||||
        reconciliation_jar.date_time = '2024-07-13 13:02:00'
 | 
					 | 
				
			||||||
        reconciliation_jar.description = "test reconcialiation jar"
 | 
					 | 
				
			||||||
        reconciliation_jar.reconcilier = 'Jorge'
 | 
					 | 
				
			||||||
        reconciliation_jar.cash_taken = jar_summary.total
 | 
					 | 
				
			||||||
        reconciliation_jar.cash_discrepancy = 0
 | 
					 | 
				
			||||||
        reconciliation_jar.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        reconciliation_jar.add_payments(jar_summary.payments)
 | 
					 | 
				
			||||||
        reconciliation_jar.clean()
 | 
					 | 
				
			||||||
        reconciliation_jar.save()
 | 
					 | 
				
			||||||
        self.assertTrue(reconciliation_jar.is_valid)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _create_two_cash_payments(self):
 | 
					 | 
				
			||||||
        cash_payment1 = Payment()
 | 
					 | 
				
			||||||
        cash_payment1.date_time = '2024-07-07 12:00:00'
 | 
					 | 
				
			||||||
        cash_payment1.type_payment = 'CASH'
 | 
					 | 
				
			||||||
        cash_payment1.amount = 132000
 | 
					 | 
				
			||||||
        cash_payment1.description = 'Saldo en compra'
 | 
					 | 
				
			||||||
        cash_payment1.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cash_payment2 = Payment()
 | 
					 | 
				
			||||||
        cash_payment2.date_time = '2024-07-07 13:05:00'
 | 
					 | 
				
			||||||
        cash_payment2.type_payment = 'CASH'
 | 
					 | 
				
			||||||
        cash_payment2.amount = 32000
 | 
					 | 
				
			||||||
        cash_payment2.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return [cash_payment1, cash_payment2]
 | 
					 | 
				
			||||||
							
								
								
									
										208
									
								
								tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								tienda_ilusion/don_confiao/tests/test_jar_reconciliation.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,208 @@
 | 
				
			|||||||
 | 
					from django.test import TestCase, Client
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
 | 
					from ..models import Sale, Product, SaleLine, Customer, ReconciliationJar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestJarReconcliation(TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        customer = Customer()
 | 
				
			||||||
 | 
					        customer.name = 'Alejo Mono'
 | 
				
			||||||
 | 
					        customer.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client = Client()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchase = Sale()
 | 
				
			||||||
 | 
					        purchase.customer = customer
 | 
				
			||||||
 | 
					        purchase.date = "2024-07-30"
 | 
				
			||||||
 | 
					        purchase.payment_method = 'CASH'
 | 
				
			||||||
 | 
					        purchase.clean()
 | 
				
			||||||
 | 
					        purchase.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        product = Product()
 | 
				
			||||||
 | 
					        product.name = "cafe"
 | 
				
			||||||
 | 
					        product.price = "72500"
 | 
				
			||||||
 | 
					        product.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line = SaleLine()
 | 
				
			||||||
 | 
					        line.sale = purchase
 | 
				
			||||||
 | 
					        line.product = product
 | 
				
			||||||
 | 
					        line.quantity = "11"
 | 
				
			||||||
 | 
					        line.unit_price = "72500"
 | 
				
			||||||
 | 
					        line.save()
 | 
				
			||||||
 | 
					        self.purchase = purchase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchase2 = Sale()
 | 
				
			||||||
 | 
					        purchase2.customer = customer
 | 
				
			||||||
 | 
					        purchase2.date = "2024-07-30"
 | 
				
			||||||
 | 
					        purchase.payment_method = 'CASH'
 | 
				
			||||||
 | 
					        purchase2.clean()
 | 
				
			||||||
 | 
					        purchase2.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line2 = SaleLine()
 | 
				
			||||||
 | 
					        line2.sale = purchase2
 | 
				
			||||||
 | 
					        line2.product = product
 | 
				
			||||||
 | 
					        line2.quantity = "27"
 | 
				
			||||||
 | 
					        line2.unit_price = "72500"
 | 
				
			||||||
 | 
					        line2.save()
 | 
				
			||||||
 | 
					        self.purchase2 = purchase2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchase3 = Sale()
 | 
				
			||||||
 | 
					        purchase3.customer = customer
 | 
				
			||||||
 | 
					        purchase3.date = "2024-07-30"
 | 
				
			||||||
 | 
					        purchase3.payment_method = 'CASH'
 | 
				
			||||||
 | 
					        purchase3.clean()
 | 
				
			||||||
 | 
					        purchase3.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line3 = SaleLine()
 | 
				
			||||||
 | 
					        line3.sale = purchase3
 | 
				
			||||||
 | 
					        line3.product = product
 | 
				
			||||||
 | 
					        line3.quantity = "37"
 | 
				
			||||||
 | 
					        line3.unit_price = "72500"
 | 
				
			||||||
 | 
					        line3.save()
 | 
				
			||||||
 | 
					        self.purchase3 = purchase3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchase4 = Sale()
 | 
				
			||||||
 | 
					        purchase4.customer = customer
 | 
				
			||||||
 | 
					        purchase4.date = "2024-07-30"
 | 
				
			||||||
 | 
					        purchase4.payment_method = 'CONFIAR'
 | 
				
			||||||
 | 
					        purchase4.clean()
 | 
				
			||||||
 | 
					        purchase4.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        line4 = SaleLine()
 | 
				
			||||||
 | 
					        line4.sale = purchase4
 | 
				
			||||||
 | 
					        line4.product = product
 | 
				
			||||||
 | 
					        line4.quantity = "47"
 | 
				
			||||||
 | 
					        line4.unit_price = "72500"
 | 
				
			||||||
 | 
					        line4.save()
 | 
				
			||||||
 | 
					        self.purchase4 = purchase4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_reconciliation_jar(self):
 | 
				
			||||||
 | 
					        reconciliation = self._create_simple_reconciliation()
 | 
				
			||||||
 | 
					        self.assertTrue(isinstance(reconciliation, ReconciliationJar))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_purchases_for_reconciliation(self):
 | 
				
			||||||
 | 
					        # link purchase to reconciliation to exclude from list
 | 
				
			||||||
 | 
					        reconciliation = self._create_simple_reconciliation()
 | 
				
			||||||
 | 
					        self.purchase3.reconciliation = reconciliation
 | 
				
			||||||
 | 
					        self.purchase3.clean()
 | 
				
			||||||
 | 
					        self.purchase3.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        url = '/don_confiao/purchases/for_reconciliation'
 | 
				
			||||||
 | 
					        response = self.client.get(url)
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rawContent = response.content.decode('utf-8')
 | 
				
			||||||
 | 
					        content = json.loads(rawContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIn('CASH', content.keys())
 | 
				
			||||||
 | 
					        self.assertIn('CONFIAR', content.keys())
 | 
				
			||||||
 | 
					        self.assertEqual(2, len(content.get('CASH')))
 | 
				
			||||||
 | 
					        self.assertEqual(1, len(content.get('CONFIAR')))
 | 
				
			||||||
 | 
					        self.assertNotIn(str(37*72500), rawContent)
 | 
				
			||||||
 | 
					        self.assertIn(str(47*72500), rawContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_don_create_reconcialiation_with_bad_numbers(self):
 | 
				
			||||||
 | 
					        reconciliation = ReconciliationJar()
 | 
				
			||||||
 | 
					        reconciliation.date_time = "2024-07-30"
 | 
				
			||||||
 | 
					        reconciliation.total_cash_purchases = 145000
 | 
				
			||||||
 | 
					        reconciliation.cash_taken = 143000
 | 
				
			||||||
 | 
					        reconciliation.cash_discrepancy = 1000
 | 
				
			||||||
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					            reconciliation.clean()
 | 
				
			||||||
 | 
					            reconciliation.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_fail_create_reconciliation_with_wrong_total_purchases_purchases(self):
 | 
				
			||||||
 | 
					        url = '/don_confiao/reconciliate_jar'
 | 
				
			||||||
 | 
					        total_purchases = (11 * 72500) + (27 * 72500)
 | 
				
			||||||
 | 
					        bad_total_purchases = total_purchases + 2
 | 
				
			||||||
 | 
					        data = {
 | 
				
			||||||
 | 
					            'date_time': '2024-12-02T21:07',
 | 
				
			||||||
 | 
					            'reconcilier': 'carlos',
 | 
				
			||||||
 | 
					            'total_cash_purchases': bad_total_purchases,
 | 
				
			||||||
 | 
					            'cash_taken': total_purchases,
 | 
				
			||||||
 | 
					            'cash_discrepancy': 0,
 | 
				
			||||||
 | 
					            'cash_purchases': [
 | 
				
			||||||
 | 
					                self.purchase.id,
 | 
				
			||||||
 | 
					                self.purchase2.id,
 | 
				
			||||||
 | 
					                self.purchase.id,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        response = self.client.post(url, data=json.dumps(data).encode('utf-8'),
 | 
				
			||||||
 | 
					                                    content_type='application/json')
 | 
				
			||||||
 | 
					        rawContent = response.content.decode('utf-8')
 | 
				
			||||||
 | 
					        content = json.loads(rawContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        self.assertIn('error', content)
 | 
				
			||||||
 | 
					        self.assertIn('total_cash_purchases', content['error'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_reconciliation_with_purchases(self):
 | 
				
			||||||
 | 
					        url = '/don_confiao/reconciliate_jar'
 | 
				
			||||||
 | 
					        total_purchases = (11 * 72500) + (27 * 72500)
 | 
				
			||||||
 | 
					        data = {
 | 
				
			||||||
 | 
					            'date_time': '2024-12-02T21:07',
 | 
				
			||||||
 | 
					            'reconcilier': 'carlos',
 | 
				
			||||||
 | 
					            'total_cash_purchases': total_purchases,
 | 
				
			||||||
 | 
					            'cash_taken': total_purchases,
 | 
				
			||||||
 | 
					            'cash_discrepancy': 0,
 | 
				
			||||||
 | 
					            'cash_purchases': [
 | 
				
			||||||
 | 
					                self.purchase.id,
 | 
				
			||||||
 | 
					                self.purchase2.id,
 | 
				
			||||||
 | 
					                self.purchase.id,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        response = self.client.post(url, data=json.dumps(data).encode('utf-8'),
 | 
				
			||||||
 | 
					                                    content_type='application/json')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rawContent = response.content.decode('utf-8')
 | 
				
			||||||
 | 
					        content = json.loads(rawContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
 | 
					        self.assertIn('id', content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchases = Sale.objects.filter(reconciliation_id=content['id'])
 | 
				
			||||||
 | 
					        self.assertEqual(len(purchases), 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_create_reconciliation_with_purchases_and_other_totals(self):
 | 
				
			||||||
 | 
					        url = '/don_confiao/reconciliate_jar'
 | 
				
			||||||
 | 
					        total_purchases = (11 * 72500) + (27 * 72500)
 | 
				
			||||||
 | 
					        data = {
 | 
				
			||||||
 | 
					            'date_time': '2024-12-02T21:07',
 | 
				
			||||||
 | 
					            'reconcilier': 'carlos',
 | 
				
			||||||
 | 
					            'total_cash_purchases': total_purchases,
 | 
				
			||||||
 | 
					            'cash_taken': total_purchases,
 | 
				
			||||||
 | 
					            'cash_discrepancy': 0,
 | 
				
			||||||
 | 
					            'cash_purchases': [
 | 
				
			||||||
 | 
					                self.purchase.id,
 | 
				
			||||||
 | 
					                self.purchase2.id,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            'other_totals': {
 | 
				
			||||||
 | 
					                'Confiar': {
 | 
				
			||||||
 | 
					                    'total': (47 * 72500) + 1,
 | 
				
			||||||
 | 
					                    'purchases': [self.purchase4.id],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        response = self.client.post(url, data=json.dumps(data).encode('utf-8'),
 | 
				
			||||||
 | 
					                                    content_type='application/json')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rawContent = response.content.decode('utf-8')
 | 
				
			||||||
 | 
					        content = json.loads(rawContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
 | 
					        self.assertIn('id', content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        purchases = Sale.objects.filter(reconciliation_id=content['id'])
 | 
				
			||||||
 | 
					        self.assertEqual(len(purchases), 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_simple_reconciliation(self):
 | 
				
			||||||
 | 
					        reconciliation = ReconciliationJar()
 | 
				
			||||||
 | 
					        reconciliation.date_time = "2024-07-30"
 | 
				
			||||||
 | 
					        reconciliation.total_cash_purchases = 0
 | 
				
			||||||
 | 
					        reconciliation.cash_taken = 0
 | 
				
			||||||
 | 
					        reconciliation.cash_discrepancy = 0
 | 
				
			||||||
 | 
					        reconciliation.clean()
 | 
				
			||||||
 | 
					        reconciliation.save()
 | 
				
			||||||
 | 
					        return reconciliation
 | 
				
			||||||
@@ -1,45 +0,0 @@
 | 
				
			|||||||
from django.test import Client, TestCase
 | 
					 | 
				
			||||||
from django.contrib.auth.models import AnonymousUser, User
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from ..models import Payment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestReconciliationJarClient(TestCase):
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        self.client = Client()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_get_summary_info_on_view(self):
 | 
					 | 
				
			||||||
        self._generate_two_cash_payments()
 | 
					 | 
				
			||||||
        response = self.client.get("/don_confiao/cuadrar_tarro")
 | 
					 | 
				
			||||||
        self.assertEqual(response.status_code, 200)
 | 
					 | 
				
			||||||
        self.assertEqual(response.context["summary"].total, 160000)
 | 
					 | 
				
			||||||
        self.assertIn('160000', response.content.decode('utf-8'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_create_reconciliation_jar(self):
 | 
					 | 
				
			||||||
        self._generate_two_cash_payments()
 | 
					 | 
				
			||||||
        response = self.client.post(
 | 
					 | 
				
			||||||
            "/don_confiao/cuadrar_tarro",
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                "date_time": "2024-07-20T00:00",
 | 
					 | 
				
			||||||
                "description": "Cuadre de prueba",
 | 
					 | 
				
			||||||
                "reconcilier": "Jorge",
 | 
					 | 
				
			||||||
                "cash_taken": "100000",
 | 
					 | 
				
			||||||
                "cash_discrepancy": "60000",
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        self.assertRedirects(response, '/don_confiao/cuadres')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _generate_two_cash_payments(self):
 | 
					 | 
				
			||||||
        cash_payment1 = Payment()
 | 
					 | 
				
			||||||
        cash_payment1.date_time = '2024-07-07 12:00:00'
 | 
					 | 
				
			||||||
        cash_payment1.type_payment = 'CASH'
 | 
					 | 
				
			||||||
        cash_payment1.amount = 130000
 | 
					 | 
				
			||||||
        cash_payment1.description = 'Saldo en compra'
 | 
					 | 
				
			||||||
        cash_payment1.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cash_payment2 = Payment()
 | 
					 | 
				
			||||||
        cash_payment2.date_time = '2024-07-07 13:05:00'
 | 
					 | 
				
			||||||
        cash_payment2.type_payment = 'CASH'
 | 
					 | 
				
			||||||
        cash_payment2.amount = 30000
 | 
					 | 
				
			||||||
        cash_payment2.save()
 | 
					 | 
				
			||||||
@@ -23,10 +23,10 @@ urlpatterns = [
 | 
				
			|||||||
    path("exportar_ventas_para_tryton",
 | 
					    path("exportar_ventas_para_tryton",
 | 
				
			||||||
         views.exportar_ventas_para_tryton,
 | 
					         views.exportar_ventas_para_tryton,
 | 
				
			||||||
         name="exportar_ventas_para_tryton"),
 | 
					         name="exportar_ventas_para_tryton"),
 | 
				
			||||||
    path("cuadrar_tarro", views.reconciliate_jar, name="reconciliate_jar"),
 | 
					 | 
				
			||||||
    path("cuadres", views.reconciliate_jar, name="reconciliations"),
 | 
					 | 
				
			||||||
    path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
 | 
					    path("resumen_compra/<int:id>", views.purchase_summary, name="purchase_summary"),
 | 
				
			||||||
    path("resumen_compra_json/<int:id>", views.purchase_json_summary, name="purchase_json_summary"),
 | 
					    path("resumen_compra_json/<int:id>", views.purchase_json_summary, name="purchase_json_summary"),
 | 
				
			||||||
    path("payment_methods/all/select_format", views.payment_methods_to_select, name="payment_methods_to_select"),
 | 
					    path("payment_methods/all/select_format", views.payment_methods_to_select, name="payment_methods_to_select"),
 | 
				
			||||||
 | 
					    path('purchases/for_reconciliation', views.sales_for_reconciliation, name='sales_for_reconciliation'),
 | 
				
			||||||
 | 
					    path('reconciliate_jar', api_views.ReconciliateJarView.as_view()),
 | 
				
			||||||
    path('api/', include(router.urls)),
 | 
					    path('api/', include(router.urls)),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,13 +4,12 @@ from django.views.generic import ListView
 | 
				
			|||||||
from django.db import transaction
 | 
					from django.db import transaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import (
 | 
					from .models import (
 | 
				
			||||||
    Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods)
 | 
					    Sale, SaleLine, Product, Customer, ProductCategory, Payment, PaymentMethods, ReconciliationJar)
 | 
				
			||||||
from .forms import (
 | 
					from .forms import (
 | 
				
			||||||
    ImportProductsForm,
 | 
					    ImportProductsForm,
 | 
				
			||||||
    ImportCustomersForm,
 | 
					    ImportCustomersForm,
 | 
				
			||||||
    PurchaseForm,
 | 
					    PurchaseForm,
 | 
				
			||||||
    SaleLineFormSet,
 | 
					    SaleLineFormSet,
 | 
				
			||||||
    ReconciliationJarForm,
 | 
					 | 
				
			||||||
    PurchaseSummaryForm)
 | 
					    PurchaseSummaryForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import csv
 | 
					import csv
 | 
				
			||||||
@@ -95,6 +94,7 @@ def import_products(request):
 | 
				
			|||||||
        {'form': form}
 | 
					        {'form': form}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def import_customers(request):
 | 
					def import_customers(request):
 | 
				
			||||||
    if request.method == "POST":
 | 
					    if request.method == "POST":
 | 
				
			||||||
        form = ImportCustomersForm(request.POST, request.FILES)
 | 
					        form = ImportCustomersForm(request.POST, request.FILES)
 | 
				
			||||||
@@ -109,24 +109,6 @@ def import_customers(request):
 | 
				
			|||||||
        {'form': form}
 | 
					        {'form': form}
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reconciliate_jar(request):
 | 
					 | 
				
			||||||
    summary = Payment.get_reconciliation_jar_summary()
 | 
					 | 
				
			||||||
    if request.method == 'POST':
 | 
					 | 
				
			||||||
        form = ReconciliationJarForm(request.POST)
 | 
					 | 
				
			||||||
        if form.is_valid():
 | 
					 | 
				
			||||||
            reconciliation = form.save()
 | 
					 | 
				
			||||||
            reconciliation.add_payments(summary.payments)
 | 
					 | 
				
			||||||
            reconciliation.clean()
 | 
					 | 
				
			||||||
            reconciliation.save()
 | 
					 | 
				
			||||||
            return HttpResponseRedirect('cuadres')
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        form = ReconciliationJarForm()
 | 
					 | 
				
			||||||
    return render(
 | 
					 | 
				
			||||||
        request,
 | 
					 | 
				
			||||||
        "don_confiao/reconciliate_jar.html",
 | 
					 | 
				
			||||||
        {'summary': summary, 'form': form}
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def reconciliations(request):
 | 
					def reconciliations(request):
 | 
				
			||||||
    return HttpResponse('<h1>Reconciliaciones</h1>')
 | 
					    return HttpResponse('<h1>Reconciliaciones</h1>')
 | 
				
			||||||
@@ -178,6 +160,24 @@ def payment_methods_to_select(request):
 | 
				
			|||||||
    return JsonResponse(methods, safe=False)
 | 
					    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):
 | 
					def _mask_phone(phone):
 | 
				
			||||||
    digits = str(phone)[-3:] if phone else " " * 3
 | 
					    digits = str(phone)[-3:] if phone else " " * 3
 | 
				
			||||||
    return "X" * 7 + digits
 | 
					    return "X" * 7 + digits
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user