refactor: split models into modules, remove template-based views, and clean up code style

- Split monolithic models.py into models/ package (customers, products, sales, payments, admin)
- Removed forms.py, all HTML templates, and associated template-based views
- Added api/ package with CatalogSaleView placeholder
- Updated all imports across project to use new model paths
- Removed obsolete tests (form, export, purchase, summary tests)
- Removed template-based URL patterns, kept only API endpoints
- Standardized string quotes (single to double) and reformatted code
This commit is contained in:
2026-05-28 15:25:27 -05:00
parent ecef46b4bb
commit f97b47081c
40 changed files with 948 additions and 1446 deletions

View File

@@ -1,6 +1,6 @@
from django.test import TestCase
from ..models import AdminCode
from ..models.admin import AdminCode
from .Mixins import LoginMixin
import json
@@ -10,33 +10,33 @@ class TestAdminCode(TestCase, LoginMixin):
def setUp(self):
self.login()
self.valid_code = 'some valid code'
self.valid_code = "some valid code"
admin_code = AdminCode()
admin_code.value = self.valid_code
admin_code.clean()
admin_code.save()
def test_validate_code(self):
url = '/don_confiao/api/admin_code/validate/' + self.valid_code
url = "/don_confiao/api/admin_code/validate/" + self.valid_code
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
self.assertTrue(content['validCode'])
content = json.loads(response.content.decode("utf-8"))
self.assertTrue(content["validCode"])
def test_invalid_code(self):
invalid_code = 'some invalid code'
url = '/don_confiao/api/admin_code/validate/' + invalid_code
invalid_code = "some invalid code"
url = "/don_confiao/api/admin_code/validate/" + invalid_code
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
self.assertFalse(content['validCode'])
content = json.loads(response.content.decode("utf-8"))
self.assertFalse(content["validCode"])
def test_empty_code(self):
empty_code = ''
url = '/don_confiao/api/admin_code/validate/' + empty_code
empty_code = ""
url = "/don_confiao/api/admin_code/validate/" + empty_code
response = self.client.get(url)
self.assertEqual(response.status_code, 404)

View File

@@ -4,7 +4,9 @@ import io
from rest_framework import status
from rest_framework.test import APITestCase
from ..models import Sale, Product, Customer
from ..models.sales import Sale
from ..models.customers import Customer
from ..models.products import Product
from .Mixins import LoginMixin
@@ -13,18 +15,15 @@ class TestAPI(APITestCase, LoginMixin):
self.login()
self.product = Product.objects.create(
name='Panela',
price=5000,
measuring_unit='UNIT'
name="Panela", price=5000, measuring_unit="UNIT"
)
self.customer = Customer.objects.create(
name='Camilo',
external_id='18'
name="Camilo", external_id="18"
)
def test_create_sale(self):
response = self._create_sale()
content = json.loads(response.content.decode('utf-8'))
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Sale.objects.count(), 1)
sale = Sale.objects.all()[0]
@@ -32,79 +31,63 @@ class TestAPI(APITestCase, LoginMixin):
sale.customer.name,
self.customer.name,
)
self.assertEqual(
sale.id,
content['id']
)
self.assertEqual(sale.id, content["id"])
self.assertIsNone(sale.external_id)
def test_create_sale_with_decimal(self):
response = self._create_sale_with_decimal()
content = json.loads(response.content.decode('utf-8'))
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Sale.objects.count(), 1)
sale = Sale.objects.all()[0]
self.assertEqual(
sale.customer.name,
self.customer.name
)
self.assertEqual(
sale.id,
content['id']
)
self.assertEqual(
sale.get_total(),
16500.00
)
self.assertEqual(sale.customer.name, self.customer.name)
self.assertEqual(sale.id, content["id"])
self.assertEqual(sale.get_total(), 16500.00)
def test_get_products(self):
url = '/don_confiao/api/products/'
url = "/don_confiao/api/products/"
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
json_response = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, 200)
self.assertEqual(self.product.name, json_response[0]['name'])
self.assertEqual(self.product.name, json_response[0]["name"])
def test_get_customers(self):
url = '/don_confiao/api/customers/'
url = "/don_confiao/api/customers/"
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
json_response = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, 200)
self.assertEqual(self.customer.name, json_response[0]['name'])
self.assertEqual(self.customer.name, json_response[0]["name"])
self.assertEqual(
self.customer.external_id,
json_response[0]['external_id']
self.customer.external_id, json_response[0]["external_id"]
)
def test_get_sales(self):
url = '/don_confiao/api/sales/'
url = "/don_confiao/api/sales/"
self._create_sale()
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
json_response = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, 200)
self.assertEqual(self.customer.id, json_response[0]['customer'])
self.assertEqual(
None,
json_response[0]['external_id']
)
self.assertEqual(self.customer.id, json_response[0]["customer"])
self.assertEqual(None, json_response[0]["external_id"])
def test_get_sales_for_tryton(self):
url = '/don_confiao/api/sales/for_tryton'
url = "/don_confiao/api/sales/for_tryton"
self._create_sale()
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
json_response = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn('csv', json_response)
self.assertGreater(len(json_response['csv']), 0)
self.assertIn("csv", json_response)
self.assertGreater(len(json_response["csv"]), 0)
def test_csv_structure_in_sales_for_tryton(self):
url = '/don_confiao/api/sales/for_tryton'
url = "/don_confiao/api/sales/for_tryton"
self._create_sale()
response = self.client.get(url)
json_response = json.loads(response.content.decode('utf-8'))
json_response = json.loads(response.content.decode("utf-8"))
self.assertEqual(response.status_code, status.HTTP_200_OK)
csv_reader = csv.reader(io.StringIO(json_response['csv']))
csv_reader = csv.reader(io.StringIO(json_response["csv"]))
expected_header = [
"Tercero",
"Dirección de facturación",
@@ -123,53 +106,115 @@ class TestAPI(APITestCase, LoginMixin):
"Tienda",
"Terminal de venta",
"Autorecogida",
"Comentario"
"Comentario",
]
self.assertEqual(next(csv_reader), expected_header)
expected_rows = [
[self.customer.name, self.customer.name, self.customer.name, "",
"", "2024-09-02", "Contado", "Almacén",
"Peso colombiano", self.product.name, "2.00", "3000.00", "Unidad",
"TIENDA LA ILUSIÓN", "Tienda La Ilusion", "La Ilusion", "True", ""
],
["", "", "", "", "", "", "", "", "", self.product.name, "3.00",
"5000.00", "Unidad", "", "", "", "", ""
],
[
self.customer.name,
self.customer.name,
self.customer.name,
"",
"",
"2024-09-02",
"Contado",
"Almacén",
"Peso colombiano",
self.product.name,
"2.00",
"3000.00",
"Unidad",
"TIENDA LA ILUSIÓN",
"Tienda La Ilusion",
"La Ilusion",
"True",
"",
],
[
"",
"",
"",
"",
"",
"",
"",
"",
"",
self.product.name,
"3.00",
"5000.00",
"Unidad",
"",
"",
"",
"",
"",
],
]
rows = list(csv_reader)
self.assertEqual(rows, expected_rows)
def _create_sale(self):
url = '/don_confiao/api/sales/'
url = "/don_confiao/api/sales/"
data = {
'customer': self.customer.id,
'date': '2024-09-02',
'payment_method': 'CASH',
'saleline_set': [
{'product': self.product.id, 'quantity': 2, 'unit_price': 3000},
{'product': self.product.id, 'quantity': 3, 'unit_price': 5000}
],
}
return self.client.post(url, data, format='json')
def _create_sale_with_decimal(self):
url = '/don_confiao/api/sales/'
data = {
'customer': self.customer.id,
'date': '2024-09-02',
'payment_method': 'CASH',
'saleline_set': [
"customer": self.customer.id,
"date": "2024-09-02",
"payment_method": "CASH",
"saleline_set": [
{
'product': self.product.id,
'quantity': 0.5,
'unit_price': 3000
"product": self.product.id,
"quantity": 2,
"unit_price": 3000,
},
{
'product': self.product.id,
'quantity': 3,
'unit_price': 5000
}
"product": self.product.id,
"quantity": 3,
"unit_price": 5000,
},
],
}
return self.client.post(url, data, format='json')
return self.client.post(url, data, format="json")
def _create_catalog_sale(self):
url = "/don_confiao/api/catalog_sales/"
data = {
"customer": self.customer.id,
"date": "2024-09-02",
"payment_method": "CASH",
"saleline_set": [
{
"product": self.product.id,
"quantity": 2,
"unit_price": 3000,
},
{
"product": self.product.id,
"quantity": 3,
"unit_price": 5000,
},
],
"catalog_sale": True,
}
return self.client.post(url, data, format="json")
def _create_sale_with_decimal(self):
url = "/don_confiao/api/sales/"
data = {
"customer": self.customer.id,
"date": "2024-09-02",
"payment_method": "CASH",
"saleline_set": [
{
"product": self.product.id,
"quantity": 0.5,
"unit_price": 3000,
},
{
"product": self.product.id,
"quantity": 3,
"unit_price": 5000,
},
],
}
return self.client.post(url, data, format="json")

View File

@@ -1,22 +0,0 @@
from django.test import Client, TestCase
from ..models import Product
class TestBuyForm(TestCase):
def setUp(self):
self.client = Client()
self.product = Product()
self.product.name = "Arroz"
self.product.price = 5000
self.product.save()
def test_buy_contains_products_list(self):
response = self.client.get('/don_confiao/comprar')
self.assertIn(
self.product.name,
response.context['list_products']
)
content = response.content.decode('utf-8')
self.assertIn('5000', content)
self.assertIn('Arroz', content)
self.assertIn(str(self.product.id), content)

View File

@@ -2,7 +2,7 @@ import json
from unittest.mock import patch
from django.test import TestCase
from ..models import Customer
from ..models.customers import Customer
from .Mixins import LoginMixin
@@ -11,61 +11,71 @@ class TestCustomersFromTryton(TestCase, LoginMixin):
self.login()
self.customer = Customer.objects.create(
name='Calos',
external_id=5
name="Calos", external_id=5
)
self.customer.save()
self.customer2 = Customer.objects.create(
name='Cristian',
external_id=6
name="Cristian", external_id=6
)
self.customer2.save()
@patch('sabatron_tryton_rpc_client.client.Client.call')
@patch('sabatron_tryton_rpc_client.client.Client.connect')
@patch("sabatron_tryton_rpc_client.client.Client.call")
@patch("sabatron_tryton_rpc_client.client.Client.connect")
def test_create_import_customer(self, mock_connect, mock_call):
def fake_call(*args, **kwargs):
party_search = 'model.party.party.search'
search_args = [[], 0, 1000, [['name', 'ASC'], ['id', None]], {'company': 1}]
party_search = "model.party.party.search"
search_args = [
[],
0,
1000,
[["name", "ASC"], ["id", None]],
{"company": 1},
]
if (args == (party_search, search_args)):
if args == (party_search, search_args):
return [5, 6, 7, 8]
party_read = 'model.party.party.read'
read_args = ([5, 6, 7, 8], ['id', 'name', 'addresses'], {'company': 1})
if (args == (party_read, read_args)):
party_read = "model.party.party.read"
read_args = (
[5, 6, 7, 8],
["id", "name", "addresses"],
{"company": 1},
)
if args == (party_read, read_args):
return [
{'id': 5, 'name': 'Carlos', 'addresses': [303]},
{'id': 6, 'name': 'Cristian', 'addresses': []},
{'id': 7, 'name': 'Ana', 'addresses': [302]},
{'id': 8, 'name': 'José', 'addresses': []},
{"id": 5, "name": "Carlos", "addresses": [303]},
{"id": 6, "name": "Cristian", "addresses": []},
{"id": 7, "name": "Ana", "addresses": [302]},
{"id": 8, "name": "José", "addresses": []},
]
raise Exception(f"Sorry, args non expected on this test: {args}")
raise Exception(
f"Sorry, args non expected on this test: {args}"
)
mock_call.side_effect = fake_call
url = '/don_confiao/api/importar_clientes_de_tryton'
url = "/don_confiao/api/importar_clientes_de_tryton"
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
content = json.loads(response.content.decode("utf-8"))
expected_response = {
'checked_tryton_parties': [5, 6, 7, 8],
'created_customers': [3, 4],
'untouched_customers': [2],
'failed_parties': [],
'updated_customers': [1]
"checked_tryton_parties": [5, 6, 7, 8],
"created_customers": [3, 4],
"untouched_customers": [2],
"failed_parties": [],
"updated_customers": [1],
}
self.assertEqual(content, expected_response)
created_customer = Customer.objects.get(id=3)
self.assertEqual(created_customer.external_id, str(7))
self.assertEqual(created_customer.name, 'Ana')
self.assertEqual(created_customer.name, "Ana")
self.assertEqual(created_customer.address_external_id, str(302))
updated_customer = Customer.objects.get(id=1)
self.assertEqual(updated_customer.external_id, str(5))
self.assertEqual(updated_customer.name, 'Carlos')
self.assertEqual(updated_customer.name, "Carlos")
self.assertIn(updated_customer.address_external_id, str(303))

View File

@@ -1,50 +0,0 @@
#!/usr/bin/env python3
from django.test import Client, TestCase
from io import StringIO
import csv
class TestExportSales(TestCase):
fixtures = ['sales_fixture']
def setUp(self):
self.client = Client()
def test_export_sales(self):
sales_response = self._export_sales_csv()
filename = sales_response.headers[
'Content-Disposition'].split('; ')[1].strip('filename=').strip("'")
content = sales_response.content
content_str = content.decode('utf-8')
csv_file = StringIO(content_str)
header = next(csv.reader(csv_file))
self.assertGreater(len(content), 0)
self.assertEqual(filename, 'sales.csv')
self.assertEqual(sales_response.headers['Content-Type'], 'text/csv')
self.assertEqual(header, self._tryton_sale_header())
def _export_sales_csv(self):
return self.client.get("/don_confiao/exportar_ventas_para_tryton")
def _tryton_sale_header(self):
return [
"Tercero",
"Dirección de facturación",
"Dirección de envío",
"Descripción",
"Referencia",
"Fecha venta",
"Plazo de pago",
"Almacén",
"Moneda",
"Líneas/Producto",
"Líneas/Cantidad",
"Líneas/Precio unitario",
"Líneas/Unidad",
"Empresa",
"Tienda",
"Terminal de venta",
"Autorecogida",
"Comentario"
]

View File

@@ -1,105 +0,0 @@
import csv
import json
from unittest.mock import patch
from django.test import TestCase
from ..models import Sale, SaleLine, Product, Customer
from .Mixins import LoginMixin
class TestExportarVentasParaTryton(TestCase, LoginMixin):
def setUp(self):
self.login()
self.product = Product.objects.create(
name='Panela',
price=5000,
measuring_unit='UNIT',
unit_external_id=1,
external_id=1
)
self.customer = Customer.objects.create(
name='Camilo',
external_id=1,
address_external_id=307,
)
self.sale = Sale.objects.create(
customer=self.customer,
date='2024-09-02',
payment_method='CASH',
description='un comentario'
)
self.sale_line1 = SaleLine.objects.create(
product=self.product,
quantity=2,
unit_price=3000,
sale=self.sale
)
self.sale_line2 = SaleLine.objects.create(
product=self.product,
quantity=3,
unit_price=5000,
sale=self.sale
)
def test_exportar_ventas_para_tryton(self):
url = '/don_confiao/exportar_ventas_para_tryton'
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'text/csv')
csv_content = response.content.decode('utf-8')
expected_header = [
"Tercero",
"Dirección de facturación",
"Dirección de envío",
"Descripción",
"Referencia",
"Fecha venta",
"Plazo de pago",
"Almacén",
"Moneda",
"Líneas/Producto",
"Líneas/Cantidad",
"Líneas/Precio unitario",
"Líneas/Unidad",
"Empresa",
"Tienda",
"Terminal de venta",
"Autorecogida",
"Comentario"
]
csv_reader = csv.reader(csv_content.splitlines())
self.assertEqual(next(csv_reader), expected_header)
expected_rows = [
["Camilo", "Camilo", "Camilo", "un comentario", "un comentario", "2024-09-02", "Contado", "Almacén", "Peso colombiano", "Panela", "2.00", "3000.00", "Unidad", "TIENDA LA ILUSIÓN", "Tienda La Ilusion", "La Ilusion", "True", "un comentario"],
["", "", "", "", "", "", "", "", "", "Panela", "3.00", "5000.00", "Unidad", "", "", "", "", ""],
]
csv_rows = list(csv_reader)
self.assertEqual(csv_rows[0], expected_rows[0])
self.assertEqual(csv_rows[1], expected_rows[1])
@patch('sabatron_tryton_rpc_client.client.Client.call')
@patch('sabatron_tryton_rpc_client.client.Client.connect')
def test_send_sales_to_tryton(self, mock_connect, mock_call):
external_id = '23423'
url = '/don_confiao/api/enviar_ventas_a_tryton'
mock_connect.return_value = None
mock_call.return_value = [external_id]
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
expected_response = {
'successful': [self.sale.id],
'failed': [],
}
self.assertEqual(content, expected_response)
updated_sale = Sale.objects.get(id=self.sale.id)
self.assertEqual(updated_sale.external_id, external_id)
mock_connect.assert_called_once()
mock_call.assert_called_once()
mock_call.assert_called_with('model.sale.sale.create', [[{'company': 1, 'shipment_address': '307', 'invoice_address': '307', 'currency': 31, 'comment': 'un comentario', 'description': 'Metodo pago: CASH', 'party': '1', 'reference': 'don_confiao 1', 'sale_date': {'__class__': 'date', 'year': 2024, 'month': 9, 'day': 2}, 'lines': [['create', [{'product': '1', 'quantity': {'__class__': 'Decimal', 'decimal': '2.00'}, 'type': 'line', 'unit': '1', 'unit_price': {'__class__': 'Decimal', 'decimal': '3000.00'}}, {'product': '1', 'quantity': {'__class__': 'Decimal', 'decimal': '3.00'}, 'type': 'line', 'unit': '1', 'unit_price': {'__class__': 'Decimal', 'decimal': '5000.00'}}]]], 'self_pick_up': True}], {'company': 1, 'shops': [1]}])

View File

@@ -1,6 +1,12 @@
from django.test import TestCase
from django.core.exceptions import ValidationError
from ..models import Sale, Product, SaleLine, Customer, ReconciliationJar
from ..models.sales import (
Sale,
Product,
SaleLine,
Customer,
ReconciliationJar,
)
from .Mixins import LoginMixin
import json
@@ -11,13 +17,13 @@ class TestJarReconcliation(TestCase, LoginMixin):
self.login()
customer = Customer()
customer.name = 'Alejo Mono'
customer.name = "Alejo Mono"
customer.save()
purchase = Sale()
purchase.customer = customer
purchase.date = "2024-07-30"
purchase.payment_method = 'CASH'
purchase.payment_method = "CASH"
purchase.clean()
purchase.save()
@@ -37,7 +43,7 @@ class TestJarReconcliation(TestCase, LoginMixin):
purchase2 = Sale()
purchase2.customer = customer
purchase2.date = "2024-07-30"
purchase.payment_method = 'CASH'
purchase.payment_method = "CASH"
purchase2.clean()
purchase2.save()
@@ -52,7 +58,7 @@ class TestJarReconcliation(TestCase, LoginMixin):
purchase3 = Sale()
purchase3.customer = customer
purchase3.date = "2024-07-30"
purchase3.payment_method = 'CASH'
purchase3.payment_method = "CASH"
purchase3.clean()
purchase3.save()
@@ -67,7 +73,7 @@ class TestJarReconcliation(TestCase, LoginMixin):
purchase4 = Sale()
purchase4.customer = customer
purchase4.date = "2024-07-30"
purchase4.payment_method = 'CONFIAR'
purchase4.payment_method = "CONFIAR"
purchase4.clean()
purchase4.save()
@@ -90,19 +96,19 @@ class TestJarReconcliation(TestCase, LoginMixin):
self.purchase3.clean()
self.purchase3.save()
url = '/don_confiao/purchases/for_reconciliation'
url = "/don_confiao/purchases/for_reconciliation"
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
rawContent = response.content.decode('utf-8')
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)
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()
@@ -114,131 +120,137 @@ class TestJarReconcliation(TestCase, LoginMixin):
reconciliation.clean()
reconciliation.save()
def test_fail_create_reconciliation_with_wrong_total_purchases_purchases(self):
url = '/don_confiao/reconciliate_jar'
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': [
"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')
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'])
self.assertIn("error", content)
self.assertIn("total_cash_purchases", content["error"])
def test_create_reconciliation_with_purchases(self):
response = self._create_reconciliation_with_purchase()
rawContent = response.content.decode('utf-8')
rawContent = response.content.decode("utf-8")
content = json.loads(rawContent)
self.assertEqual(response.status_code, 200)
self.assertIn('id', content)
self.assertIn("id", content)
purchases = Sale.objects.filter(reconciliation_id=content['id'])
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'
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': [
"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],
"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')
response = self.client.post(
url,
data=json.dumps(data).encode("utf-8"),
content_type="application/json",
)
rawContent = response.content.decode('utf-8')
rawContent = response.content.decode("utf-8")
content = json.loads(rawContent)
self.assertEqual(response.status_code, 200)
self.assertIn('id', content)
self.assertIn("id", content)
purchases = Sale.objects.filter(reconciliation_id=content['id'])
purchases = Sale.objects.filter(reconciliation_id=content["id"])
self.assertEqual(len(purchases), 3)
def test_list_reconciliations(self):
self._create_simple_reconciliation()
self._create_simple_reconciliation()
url = '/don_confiao/api/reconciliate_jar/'
url = "/don_confiao/api/reconciliate_jar/"
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
self.assertEqual(2, content['count'])
self.assertEqual(2, len(content['results']))
self.assertEqual('2024-07-30T00:00:00Z',
content['results'][0]['date_time'])
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(2, content["count"])
self.assertEqual(2, len(content["results"]))
self.assertEqual(
"2024-07-30T00:00:00Z", content["results"][0]["date_time"]
)
def test_list_reconciliations_pagination(self):
self._create_simple_reconciliation()
self._create_simple_reconciliation()
url = '/don_confiao/api/reconciliate_jar/?page=2&page_size=1'
url = "/don_confiao/api/reconciliate_jar/?page=2&page_size=1"
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
self.assertEqual(1, len(content['results']))
self.assertEqual('2024-07-30T00:00:00Z',
content['results'][0]['date_time'])
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(1, len(content["results"]))
self.assertEqual(
"2024-07-30T00:00:00Z", content["results"][0]["date_time"]
)
def test_get_single_reconciliation(self):
createResponse = self._create_reconciliation_with_purchase()
reconciliationId = json.loads(
createResponse.content.decode('utf-8')
)['id']
createResponse.content.decode("utf-8")
)["id"]
self.assertGreater(reconciliationId, 0)
url = f'/don_confiao/api/reconciliate_jar/{reconciliationId}/'
response = self.client.get(url, content_type='application/json')
content = json.loads(
response.content.decode('utf-8')
)
self.assertEqual(reconciliationId, content['id'])
self.assertGreater(len(content['Sales']), 0)
url = f"/don_confiao/api/reconciliate_jar/{reconciliationId}/"
response = self.client.get(url, content_type="application/json")
content = json.loads(response.content.decode("utf-8"))
self.assertEqual(reconciliationId, content["id"])
self.assertGreater(len(content["Sales"]), 0)
self.assertIn(
self.purchase.id,
[sale['id'] for sale in content['Sales']]
self.purchase.id, [sale["id"] for sale in content["Sales"]]
)
self.assertIn(
'CASH',
[sale['payment_method'] for sale in content['Sales']]
"CASH", [sale["payment_method"] for sale in content["Sales"]]
)
def test_create_reconciliation_with_decimal_on_sale_lines(self):
customer = Customer()
customer.name = 'Consumidor final'
customer.name = "Consumidor final"
customer.save()
product = Product()
@@ -249,7 +261,7 @@ class TestJarReconcliation(TestCase, LoginMixin):
purchase = Sale()
purchase.customer = customer
purchase.date = "2024-07-30"
purchase.payment_method = 'CASH'
purchase.payment_method = "CASH"
purchase.clean()
purchase.save()
@@ -260,23 +272,23 @@ class TestJarReconcliation(TestCase, LoginMixin):
line.unit_price = "57.50"
line.save()
url = '/don_confiao/reconciliate_jar'
url = "/don_confiao/reconciliate_jar"
total_purchases = 13.80
data = {
'date_time': '2024-12-02T21:07',
'reconcilier': 'carlos',
'total_cash_purchases': total_purchases,
'cash_taken': total_purchases,
'cash_discrepancy': 0,
'cash_purchases': [purchase.id],
"date_time": "2024-12-02T21:07",
"reconcilier": "carlos",
"total_cash_purchases": total_purchases,
"cash_taken": total_purchases,
"cash_discrepancy": 0,
"cash_purchases": [purchase.id],
}
response = self.client.post(
url, data=json.dumps(data).encode('utf-8'),
content_type='application/json'
url,
data=json.dumps(data).encode("utf-8"),
content_type="application/json",
)
self.assertEqual(response.status_code, 200)
def _create_simple_reconciliation(self):
reconciliation = ReconciliationJar()
reconciliation.date_time = "2024-07-30"
@@ -288,19 +300,22 @@ class TestJarReconcliation(TestCase, LoginMixin):
return reconciliation
def _create_reconciliation_with_purchase(self):
url = '/don_confiao/reconciliate_jar'
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': [
"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,
],
}
return self.client.post(url, data=json.dumps(data).encode('utf-8'),
content_type='application/json')
return self.client.post(
url,
data=json.dumps(data).encode("utf-8"),
content_type="application/json",
)

View File

@@ -2,7 +2,7 @@
from django.test import TestCase
from django.db.utils import IntegrityError
from ..models import Customer
from ..models.customers import Customer
class TestCustomer(TestCase):

View File

@@ -1,6 +1,6 @@
from django.test import Client, TestCase
from django.conf import settings
from ..models import ProductCategory, Product
from ..models.products import ProductCategory, Product
import os
import json
@@ -20,24 +20,6 @@ class TestProducts(TestCase):
self.assertIsNone(product.external_id)
self.assertIsNone(product.unit_external_id)
def test_import_products(self):
self._import_csv()
all_products = self._get_products()
self.assertEqual(len(all_products), 3)
def test_import_products_with_categories(self):
self._import_csv()
all_products = self._get_products()
self.assertIn("Aceites", all_products[0]["categories"])
def test_don_repeat_categories_on_import(self):
self._import_csv()
categories_on_csv = ["Cafes", "Alimentos", "Aceites"]
categories = ProductCategory.objects.all()
self.assertCountEqual(
[c.name for c in categories], categories_on_csv
)
def test_update_products(self):
self._import_csv()
first_products = self._get_products()
@@ -45,55 +27,6 @@ class TestProducts(TestCase):
seconds_products = self._get_products()
self.assertEqual(len(first_products), len(seconds_products))
def test_preserve_id_on_import(self):
self._import_csv()
id_aceite = Product.objects.get(name="Aceite").id
self._import_csv("example_products2.csv")
id_post_updated = Product.objects.get(name="Aceite").id
self.assertEqual(id_aceite, id_post_updated)
def test_update_categories_on_import(self):
self._import_csv()
first_products = self._get_products()
first_categories = {
p["name"]: p["categories"] for p in first_products
}
self._import_csv("example_products2.csv")
updated_products = self._get_products()
updated_categories = {
p["name"]: p["categories"] for p in updated_products
}
self.assertIn("Cafes", first_categories["Arroz"])
self.assertNotIn("Granos", first_categories["Arroz"])
self.assertIn("Granos", updated_categories["Arroz"])
self.assertNotIn("Cafes", updated_categories["Arroz"])
def test_update_price(self):
self._import_csv()
first_products = self._get_products()
first_prices = {p["name"]: p["price_list"] for p in first_products}
expected_first_prices = {
"Aceite": "50000.00",
"Café": "14000.00",
"Arroz": "7000.00",
}
self.assertDictEqual(expected_first_prices, first_prices)
self._import_csv("example_products2.csv")
updated_products = self._get_products()
updated_prices = {
p["name"]: p["price_list"] for p in updated_products
}
expected_updated_prices = {
"Aceite": "50000.00",
"Café": "15000.00",
"Arroz": "6000.00",
}
self.assertDictEqual(expected_updated_prices, updated_prices)
def _get_products(self):
products_response = self.client.get("/don_confiao/productos")
return json.loads(products_response.content.decode("utf-8"))

View File

@@ -3,7 +3,7 @@ from decimal import Decimal
from unittest.mock import patch
from django.test import TestCase
from ..models import Product
from ..models.products import Product
from .Mixins import LoginMixin
@@ -12,120 +12,163 @@ class TestProductsFromTryton(TestCase, LoginMixin):
self.login()
self.product = Product.objects.create(
name='Panela',
name="Panela",
price=5000,
measuring_unit='UNIT',
measuring_unit="UNIT",
unit_external_id=1,
external_id=191
external_id=191,
)
self.product.save()
self.product2 = Product.objects.create(
name='Papa',
name="Papa",
price=4500,
measuring_unit='Kilogram',
measuring_unit="Kilogram",
unit_external_id=2,
external_id=192
external_id=192,
)
self.product2.save()
@patch('sabatron_tryton_rpc_client.client.Client.call')
@patch('sabatron_tryton_rpc_client.client.Client.connect')
@patch("sabatron_tryton_rpc_client.client.Client.call")
@patch("sabatron_tryton_rpc_client.client.Client.connect")
def test_create_import_products(self, mock_connect, mock_call):
mock_connect.return_value = None
def fake_call(*args, **kwargs):
product_search = 'model.product.product.search'
search_args = [[["salable", "=", True]], 0, 1000, [['rec_name', 'ASC'], ['id', None]], {'company': 1}]
if (args == (product_search, search_args)):
product_search = "model.product.product.search"
search_args = [
[["salable", "=", True]],
0,
1000,
[["rec_name", "ASC"], ["id", None]],
{"company": 1},
]
if args == (product_search, search_args):
return [190, 191, 192]
product_read = 'model.product.product.read'
product_args = ([190, 191, 192],
['id', 'name', 'default_uom.id',
'default_uom.rec_name', 'list_price'],
{'company': 1}
)
if (args == (product_read, product_args)):
product_read = "model.product.product.read"
product_args = (
[190, 191, 192],
[
"id",
"name",
"default_uom.id",
"default_uom.rec_name",
"list_price",
],
{"company": 1},
)
if args == (product_read, product_args):
return [
{'id': 190, 'list_price': Decimal('25000'),
'name': 'Producto 1',
'default_uom.': {'id': 1, 'rec_name': 'Unit'}},
{'id': 191, 'list_price': Decimal('6000'),
'name': 'Panela2',
'default_uom.': {'id': 1, 'rec_name': 'Unit'}},
{'id': 192, 'list_price': Decimal('4500'),
'name': 'Papa',
'default_uom.': {'id': 2, 'rec_name': 'Kilogram'}},
{
"id": 190,
"list_price": Decimal("25000"),
"name": "Producto 1",
"default_uom.": {"id": 1, "rec_name": "Unit"},
},
{
"id": 191,
"list_price": Decimal("6000"),
"name": "Panela2",
"default_uom.": {"id": 1, "rec_name": "Unit"},
},
{
"id": 192,
"list_price": Decimal("4500"),
"name": "Papa",
"default_uom.": {"id": 2, "rec_name": "Kilogram"},
},
]
raise Exception(f"Sorry, args non expected on this test: {args}")
raise Exception(
f"Sorry, args non expected on this test: {args}"
)
mock_call.side_effect = fake_call
url = '/don_confiao/api/importar_productos_de_tryton'
url = "/don_confiao/api/importar_productos_de_tryton"
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
content = json.loads(response.content.decode("utf-8"))
expected_response = {
'checked_tryton_products': [190, 191, 192],
'created_products': [3],
'untouched_products': [2],
'failed_products': [],
'updated_products': [1]
"checked_tryton_products": [190, 191, 192],
"created_products": [3],
"untouched_products": [2],
"failed_products": [],
"updated_products": [1],
}
self.assertEqual(content, expected_response)
created_product = Product.objects.get(id=3)
self.assertEqual(created_product.external_id, str(190))
self.assertEqual(created_product.name, 'Producto 1')
self.assertEqual(created_product.price, Decimal('25000'))
self.assertEqual(created_product.measuring_unit, 'Unit')
self.assertEqual(created_product.name, "Producto 1")
self.assertEqual(created_product.price, Decimal("25000"))
self.assertEqual(created_product.measuring_unit, "Unit")
updated_product = Product.objects.get(id=1)
self.assertEqual(updated_product.external_id, str(191))
self.assertEqual(updated_product.name, 'Panela2')
self.assertEqual(updated_product.price, Decimal('6000'))
self.assertEqual(updated_product.measuring_unit, 'Unit')
self.assertEqual(updated_product.name, "Panela2")
self.assertEqual(updated_product.price, Decimal("6000"))
self.assertEqual(updated_product.measuring_unit, "Unit")
@patch('sabatron_tryton_rpc_client.client.Client.call')
@patch('sabatron_tryton_rpc_client.client.Client.connect')
def test_import_duplicated_name_products(self, mock_connect, mock_call):
@patch("sabatron_tryton_rpc_client.client.Client.call")
@patch("sabatron_tryton_rpc_client.client.Client.connect")
def test_import_duplicated_name_products(
self, mock_connect, mock_call
):
mock_connect.return_value = None
def fake_call(*args, **kwargs):
product_search = 'model.product.product.search'
search_args = [[["salable", "=", True]], 0, 1000, [['rec_name', 'ASC'], ['id', None]], {'company': 1}]
if (args == (product_search, search_args)):
product_search = "model.product.product.search"
search_args = [
[["salable", "=", True]],
0,
1000,
[["rec_name", "ASC"], ["id", None]],
{"company": 1},
]
if args == (product_search, search_args):
return [200]
product_read = 'model.product.product.read'
product_args = ([200],
['id', 'name', 'default_uom.id',
'default_uom.rec_name', 'list_price'],
{'company': 1}
)
if (args == (product_read, product_args)):
product_read = "model.product.product.read"
product_args = (
[200],
[
"id",
"name",
"default_uom.id",
"default_uom.rec_name",
"list_price",
],
{"company": 1},
)
if args == (product_read, product_args):
return [
{'id': 200, 'list_price': Decimal('25000'),
'name': self.product.name,
'default_uom.': {'id': 1, 'rec_name': 'Unit'}},
{
"id": 200,
"list_price": Decimal("25000"),
"name": self.product.name,
"default_uom.": {"id": 1, "rec_name": "Unit"},
},
]
raise Exception(f"Sorry, args non expected on this test: {args}")
raise Exception(
f"Sorry, args non expected on this test: {args}"
)
mock_call.side_effect = fake_call
url = '/don_confiao/api/importar_productos_de_tryton'
url = "/don_confiao/api/importar_productos_de_tryton"
response = self.client.post(url)
self.assertEqual(response.status_code, 200)
content = json.loads(response.content.decode('utf-8'))
content = json.loads(response.content.decode("utf-8"))
expected_response = {
'checked_tryton_products': [200],
'created_products': [],
'untouched_products': [],
'failed_products': [200],
'updated_products': [],
"checked_tryton_products": [200],
"created_products": [],
"untouched_products": [],
"failed_products": [200],
"updated_products": [],
}
self.assertEqual(content, expected_response)

View File

@@ -1,51 +0,0 @@
from django.test import Client, TestCase
from ..models import Payment, Sale, Product, Customer
class TestPurchaseWithPayment(TestCase):
def setUp(self):
self.client = Client()
self.product = Product()
self.product.name = "Arroz"
self.product.price = 5000
self.product.save()
customer = Customer()
customer.name = "Noelba Lopez"
customer.save()
self.customer = customer
def test_generate_payment_when_it_has_payment(self):
quantity = 2
unit_price = 2500
total = 5000
self.client.post(
'/don_confiao/comprar',
{
"customer": str(self.customer.id),
"date": "2024-07-27",
"phone": "3010101000",
"description": "Venta de contado",
"saleline_set-TOTAL_FORMS": "1",
"saleline_set-INITIAL_FORMS": "0",
"saleline_set-MIN_NUM_FORMS": "0",
"saleline_set-MAX_NUM_FORMS": "1000",
"saleline_set-0-product": str(self.product.id),
"saleline_set-0-quantity": str(quantity),
"saleline_set-0-unit_price": str(unit_price),
"saleline_set-0-description": "Linea de Venta",
"saleline_set-0-sale": "",
"saleline_set-0-id": "",
"quantity_lines": "1",
"quantity_products": str(quantity),
"ammount": str(quantity * unit_price),
"payment_method": "CASH",
}
)
purchases = Sale.objects.all()
self.assertEqual(1, len(purchases))
payments = Payment.objects.all()
self.assertEqual(1, len(payments))
self.assertEqual(total, payments[0].amount)
self.assertEqual('CASH', payments[0].type_payment)

View File

@@ -1,55 +0,0 @@
from django.test import TestCase
from ..models import Sale, Product, SaleLine, Customer
from .Mixins import LoginMixin
class TestSummaryViewPurchase(TestCase, LoginMixin):
def setUp(self):
self.login()
customer = Customer()
customer.name = 'Alejo Mono'
customer.save()
purchase = Sale()
purchase.customer = customer
purchase.date = "2024-07-30"
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
def test_summary_has_customer(self):
url = "/don_confiao/resumen_compra/" + str(self.purchase.id)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context["purchase"].customer,
self.purchase.customer
)
self.assertIn('Alejo Mono', response.content.decode('utf-8'))
def test_json_summary(self):
url = f"/don_confiao/resumen_compra_json/{self.purchase.id}"
response = self.client.get(url)
content = response.content.decode('utf-8')
self.assertEqual(response.status_code, 200)
self.assertIn('Alejo Mono', content)
self.assertIn('cafe', content)
self.assertIn('72500', content)
self.assertIn('quantity', content)
self.assertIn('11', content)
self.assertIn('date', content)
self.assertIn(self.purchase.date, content)
self.assertIn('lines', content)

View File

@@ -1,7 +1,9 @@
from django.test import TestCase
from django.core.exceptions import ValidationError
from ..models import Customer, Product, Sale, SaleLine
from ..models.customers import Customer
from ..models.products import Product
from ..models.sales import Sale, SaleLine
class ConfiaoTest(TestCase):
@@ -20,7 +22,7 @@ class ConfiaoTest(TestCase):
sale = Sale()
sale.customer = self.customer
sale.date = "2024-06-22 12:05:00"
sale.phone = '666666666'
sale.phone = "666666666"
sale.description = "Description"
sale.save()
@@ -30,9 +32,9 @@ class ConfiaoTest(TestCase):
sale = Sale()
sale.customer = self.customer
sale.date = "2024-06-22 12:05:00"
sale.phone = '666666666'
sale.phone = "666666666"
sale.description = "Description"
sale.payment_method = ''
sale.payment_method = ""
with self.assertRaises(ValidationError):
sale.full_clean()
@@ -41,7 +43,7 @@ class ConfiaoTest(TestCase):
sale = Sale()
sale.customer = self.customer
sale.date = "2024-06-22"
sale.phone = '666666666'
sale.phone = "666666666"
sale.description = "Description"
line = SaleLine()
@@ -58,7 +60,7 @@ class ConfiaoTest(TestCase):
sale = Sale()
sale.customer = self.customer
sale.date = "2024-06-22"
sale.phone = '666666666'
sale.phone = "666666666"
sale.description = "Description"
line1 = SaleLine()
@@ -81,15 +83,14 @@ class ConfiaoTest(TestCase):
self.assertEqual(len(SaleLine.objects.all()), 2)
self.assertEqual(
Sale.objects.all()[0].saleline_set.all()[0].quantity,
2
Sale.objects.all()[0].saleline_set.all()[0].quantity, 2
)
def test_allow_sale_without_description(self):
sale = Sale()
sale.customer = self.customer
sale.date = "2024-06-22"
sale.phone = '666666666'
sale.phone = "666666666"
sale.description = None
sale.save()

View File

@@ -1,45 +0,0 @@
#!/usr/bin/env python3
from django.test import TestCase
from ..forms import PurchaseForm
from ..models import Customer
_csrf_token = \
"bVjBevJRavxRPFOlVgAWiyh9ceuiwPlyEcmbPZprNuCGHjFZRKZrBeunJvKTRgOx"
class PurchaseFormTest(TestCase):
def setUp(self):
self.customer = Customer()
self.customer.name = "Don Confiao Gonzalez"
self.customer.address = "Patio Bonito"
self.customer.save()
def test_add_purchase(self):
form_data = {
"csrfmiddlewaretoken": _csrf_token,
"customer": self.customer.id,
"date": "2024-08-03",
"payment_method": "CASH",
"phone": "sfasfd",
"description": "dasdadad",
"saleline_set-TOTAL_FORMS": "1",
"saleline_set-INITIAL_FORMS": "0",
"saleline_set-MIN_NUM_FORMS": "0",
"saleline_set-MAX_NUM_FORMS": "1000",
"saleline_set-0-product": "5",
"saleline_set-0-quantity": "1",
"saleline_set-0-unit_price": "500",
"saleline_set-0-description": "afasdfasdf",
"saleline_set-0-sale": "",
"saleline_set-0-id": "",
"quantity_lines": "1",
"quantity_products": "1",
"ammount": "500",
"form": ""
}
purchase_form = PurchaseForm(data=form_data)
purchase_form.is_valid()
# raise Exception(purchase_form)
self.assertTrue(purchase_form.is_valid())