diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 2c59616..1258459 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 14d9844..ae045be 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index f56ddce..7cb98ef 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/migrations/0026_purchaseorder_purchase_purchase_order_and_more.py b/core/migrations/0026_purchaseorder_purchase_purchase_order_and_more.py new file mode 100644 index 0000000..48e2693 --- /dev/null +++ b/core/migrations/0026_purchaseorder_purchase_purchase_order_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 5.2.7 on 2026-02-06 05:45 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0025_sale_subtotal_sale_vat_amount'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='PurchaseOrder', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('lpo_number', models.CharField(blank=True, max_length=50, verbose_name='LPO Number')), + ('total_amount', models.DecimalField(decimal_places=3, max_digits=15, verbose_name='Total Amount')), + ('status', models.CharField(choices=[('draft', 'Draft'), ('sent', 'Sent'), ('converted', 'Converted to Purchase'), ('cancelled', 'Cancelled')], default='draft', max_length=20, verbose_name='Status')), + ('issue_date', models.DateField(default=django.utils.timezone.now, verbose_name='Issue Date')), + ('expected_date', models.DateField(blank=True, null=True, verbose_name='Expected Date')), + ('notes', models.TextField(blank=True, verbose_name='Notes')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_orders', to=settings.AUTH_USER_MODEL)), + ('supplier', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_orders', to='core.supplier')), + ], + ), + migrations.AddField( + model_name='purchase', + name='purchase_order', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='converted_purchase', to='core.purchaseorder'), + ), + migrations.CreateModel( + name='PurchaseOrderItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='Quantity')), + ('cost_price', models.DecimalField(decimal_places=3, max_digits=12, verbose_name='Cost Price')), + ('line_total', models.DecimalField(decimal_places=3, max_digits=15, verbose_name='Line Total')), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.product')), + ('purchase_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='core.purchaseorder')), + ], + ), + ] diff --git a/core/migrations/__pycache__/0026_purchaseorder_purchase_purchase_order_and_more.cpython-311.pyc b/core/migrations/__pycache__/0026_purchaseorder_purchase_purchase_order_and_more.cpython-311.pyc new file mode 100644 index 0000000..c056e18 Binary files /dev/null and b/core/migrations/__pycache__/0026_purchaseorder_purchase_purchase_order_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 41dcb05..cc3eb67 100644 --- a/core/models.py +++ b/core/models.py @@ -232,6 +232,37 @@ class QuotationItem(models.Model): def __str__(self): return f"{self.product.name_en} x {self.quantity}" +class PurchaseOrder(models.Model): + STATUS_CHOICES = [ + ('draft', _('Draft')), + ('sent', _('Sent')), + ('converted', _('Converted to Purchase')), + ('cancelled', _('Cancelled')), + ] + + supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, related_name="purchase_orders") + lpo_number = models.CharField(_("LPO Number"), max_length=50, blank=True) + total_amount = models.DecimalField(_("Total Amount"), max_digits=15, decimal_places=3) + status = models.CharField(_("Status"), max_length=20, choices=STATUS_CHOICES, default='draft') + issue_date = models.DateField(_("Issue Date"), default=timezone.now) + expected_date = models.DateField(_("Expected Date"), null=True, blank=True) + notes = models.TextField(_("Notes"), blank=True) + created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="purchase_orders") + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"LPO #{self.id} - {self.supplier.name if self.supplier else 'N/A'}" + +class PurchaseOrderItem(models.Model): + purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.CASCADE, related_name="items") + product = models.ForeignKey(Product, on_delete=models.CASCADE) + quantity = models.DecimalField(_("Quantity"), max_digits=15, decimal_places=2) + cost_price = models.DecimalField(_("Cost Price"), max_digits=12, decimal_places=3) + line_total = models.DecimalField(_("Line Total"), max_digits=15, decimal_places=3) + + def __str__(self): + return f"{self.product.name_en} x {self.quantity}" + class Purchase(models.Model): PAYMENT_TYPE_CHOICES = [ ('cash', _('Cash')), @@ -245,6 +276,7 @@ class Purchase(models.Model): ] supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, related_name="purchases") + purchase_order = models.ForeignKey(PurchaseOrder, on_delete=models.SET_NULL, null=True, blank=True, related_name="converted_purchase") invoice_number = models.CharField(_("Invoice Number"), max_length=50, blank=True) total_amount = models.DecimalField(_("Total Amount"), max_digits=15, decimal_places=3) paid_amount = models.DecimalField(_("Paid Amount"), max_digits=15, decimal_places=3, default=0) diff --git a/core/templates/base.html b/core/templates/base.html index ab40dcd..e126f04 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -93,6 +93,11 @@