update
BIN
.idea/.DS_Store
generated
vendored
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-28 15:50
|
||||
# Generated by Django 5.1.5 on 2025-01-30 11:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ from django.conf import settings
|
||||
from django.conf.urls.i18n import i18n_patterns
|
||||
from inventory import views
|
||||
import debug_toolbar
|
||||
from two_factor.urls import urlpatterns as tf_urls
|
||||
|
||||
urlpatterns = [
|
||||
path('__debug__/', include(debug_toolbar.urls)),
|
||||
@ -24,7 +25,8 @@ urlpatterns += i18n_patterns(
|
||||
path('ledger/', include('django_ledger.urls', namespace='django_ledger')),
|
||||
path("haikalbot/", include("haikalbot.urls")),
|
||||
path('appointment/', include('appointment.urls')),
|
||||
# path('plans/', include('plans.urls')),
|
||||
path('plans/', include('plans.urls')),
|
||||
path('', include(tf_urls)),
|
||||
)
|
||||
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
249082
carequipment_backup_015528012025.json
Normal file
4112
carmake_updated_backup.json
Normal file
47675
carmodel_backup_015028012025.json
Normal file
338249
caroption_backup_015528012025.json
Normal file
17738173
caroptionvalue_backup_015528012025.json
Normal file
190934
carserie_backup_015528012025.json
Normal file
830
carspecification_backup_015528012025.json
Normal file
@ -0,0 +1,830 @@
|
||||
[
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Bodywork",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"name": "Body type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"name": "Number of doors",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1549
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 4,
|
||||
"fields": {
|
||||
"name": "Number of seater",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 5,
|
||||
"fields": {
|
||||
"name": "Length",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 6,
|
||||
"fields": {
|
||||
"name": "Width",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 7,
|
||||
"fields": {
|
||||
"name": "Height",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 8,
|
||||
"fields": {
|
||||
"name": "Wheelbase",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 9,
|
||||
"fields": {
|
||||
"name": "Front track",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 10,
|
||||
"fields": {
|
||||
"name": "Rear track",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 11,
|
||||
"fields": {
|
||||
"name": "Engine",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 12,
|
||||
"fields": {
|
||||
"name": "Engine type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 13,
|
||||
"fields": {
|
||||
"name": "Capacity",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 14,
|
||||
"fields": {
|
||||
"name": "Engine power",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 15,
|
||||
"fields": {
|
||||
"name": "Max power at RPM",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 16,
|
||||
"fields": {
|
||||
"name": "Maximum torque",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 17,
|
||||
"fields": {
|
||||
"name": "Injection type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 19,
|
||||
"fields": {
|
||||
"name": "Cylinder layout",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 20,
|
||||
"fields": {
|
||||
"name": "Number of cylinders",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 21,
|
||||
"fields": {
|
||||
"name": "Compression ratio",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 22,
|
||||
"fields": {
|
||||
"name": "Fuel",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 23,
|
||||
"fields": {
|
||||
"name": "Gearbox and handling",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 24,
|
||||
"fields": {
|
||||
"name": "Gearbox type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 23
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 26,
|
||||
"fields": {
|
||||
"name": "Number of gear",
|
||||
"arabic_name": "",
|
||||
"id_parent": 23
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 27,
|
||||
"fields": {
|
||||
"name": "Drive wheels",
|
||||
"arabic_name": "",
|
||||
"id_parent": 23
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 29,
|
||||
"fields": {
|
||||
"name": "Front brakes",
|
||||
"arabic_name": "",
|
||||
"id_parent": 40
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 30,
|
||||
"fields": {
|
||||
"name": "Rear brakes",
|
||||
"arabic_name": "",
|
||||
"id_parent": 40
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 31,
|
||||
"fields": {
|
||||
"name": "Operating characteristics",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 32,
|
||||
"fields": {
|
||||
"name": "Max speed",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 33,
|
||||
"fields": {
|
||||
"name": "Acceleration (0-100 km/h)",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 34,
|
||||
"fields": {
|
||||
"name": "Curb weight",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 35,
|
||||
"fields": {
|
||||
"name": "Fuel tank capacity",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 36,
|
||||
"fields": {
|
||||
"name": "Wheel size",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 37,
|
||||
"fields": {
|
||||
"name": "Emission standards",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 38,
|
||||
"fields": {
|
||||
"name": "Ground clearance",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 39,
|
||||
"fields": {
|
||||
"name": "Valves per cylinder",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 40,
|
||||
"fields": {
|
||||
"name": "Suspension and brakes",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 41,
|
||||
"fields": {
|
||||
"name": "Front suspension",
|
||||
"arabic_name": "",
|
||||
"id_parent": 40
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 42,
|
||||
"fields": {
|
||||
"name": "Back suspension",
|
||||
"arabic_name": "",
|
||||
"id_parent": 40
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 44,
|
||||
"fields": {
|
||||
"name": "Max trunk capacity",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 45,
|
||||
"fields": {
|
||||
"name": "Min trunk capacity",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 46,
|
||||
"fields": {
|
||||
"name": "Boost type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 47,
|
||||
"fields": {
|
||||
"name": "Cylinder bore",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 48,
|
||||
"fields": {
|
||||
"name": "Stroke cycle",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 50,
|
||||
"fields": {
|
||||
"name": "City driving fuel consumption per 100 km",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 51,
|
||||
"fields": {
|
||||
"name": "Highway driving fuel consumption per 100 km",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 52,
|
||||
"fields": {
|
||||
"name": "Mixed driving fuel consumption per 100 km",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 55,
|
||||
"fields": {
|
||||
"name": "Engine model",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 57,
|
||||
"fields": {
|
||||
"name": "Turning circle",
|
||||
"arabic_name": "",
|
||||
"id_parent": 23
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 58,
|
||||
"fields": {
|
||||
"name": "Full weight",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 59,
|
||||
"fields": {
|
||||
"name": "Disc size",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 61,
|
||||
"fields": {
|
||||
"name": "Engine placement",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 62,
|
||||
"fields": {
|
||||
"name": "Cruising range",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 66,
|
||||
"fields": {
|
||||
"name": "Car width with mirrors",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1549,
|
||||
"fields": {
|
||||
"name": "General information",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1551,
|
||||
"fields": {
|
||||
"name": "Safety",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1552,
|
||||
"fields": {
|
||||
"name": "Country",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1549
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1553,
|
||||
"fields": {
|
||||
"name": "Car class",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1549
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1554,
|
||||
"fields": {
|
||||
"name": "Clearance",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1555,
|
||||
"fields": {
|
||||
"name": "Front track width",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1556,
|
||||
"fields": {
|
||||
"name": "Back track width",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1559,
|
||||
"fields": {
|
||||
"name": "Max power (kW)",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1561,
|
||||
"fields": {
|
||||
"name": "CO2 emissions",
|
||||
"arabic_name": "",
|
||||
"id_parent": 31
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1562,
|
||||
"fields": {
|
||||
"name": "Safety assessment",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1551
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1563,
|
||||
"fields": {
|
||||
"name": "Rating name",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1551
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1564,
|
||||
"fields": {
|
||||
"name": "Turnover of maximum torque",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1565,
|
||||
"fields": {
|
||||
"name": "Payload",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1566,
|
||||
"fields": {
|
||||
"name": "Presence of intercooler",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1567,
|
||||
"fields": {
|
||||
"name": "Trailer load (with brakes)",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1568,
|
||||
"fields": {
|
||||
"name": "Front/rear axle load",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1569,
|
||||
"fields": {
|
||||
"name": "Loading height",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1570,
|
||||
"fields": {
|
||||
"name": "Cargo compartment (Length x Width x Height)",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1571,
|
||||
"fields": {
|
||||
"name": "Cargo compartment volume",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1631,
|
||||
"fields": {
|
||||
"name": "Accumulator battery",
|
||||
"arabic_name": "",
|
||||
"id_parent": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1632,
|
||||
"fields": {
|
||||
"name": "Battery capacity",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1634,
|
||||
"fields": {
|
||||
"name": "Electric power reserve",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1635,
|
||||
"fields": {
|
||||
"name": "Charging time",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1641,
|
||||
"fields": {
|
||||
"name": "Steering wheel position",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1549
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1642,
|
||||
"fields": {
|
||||
"name": "Dimensions",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1644,
|
||||
"fields": {
|
||||
"name": "Pitch Circle Diameter",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1645,
|
||||
"fields": {
|
||||
"name": "Engine code",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1647,
|
||||
"fields": {
|
||||
"name": "Battery type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1648,
|
||||
"fields": {
|
||||
"name": "Timing belt",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1649,
|
||||
"fields": {
|
||||
"name": "Flow calculation method",
|
||||
"arabic_name": "",
|
||||
"id_parent": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1650,
|
||||
"fields": {
|
||||
"name": "Battery temperature",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1651,
|
||||
"fields": {
|
||||
"name": "Fast charge time",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1652,
|
||||
"fields": {
|
||||
"name": "Description of fast charging",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1653,
|
||||
"fields": {
|
||||
"name": "Charging connector type",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1654,
|
||||
"fields": {
|
||||
"name": "Consumption",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1655,
|
||||
"fields": {
|
||||
"name": "Maximum charging power",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1656,
|
||||
"fields": {
|
||||
"name": "Battery capacity (available)",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "inventory.carspecification",
|
||||
"pk": 1657,
|
||||
"fields": {
|
||||
"name": "Number of charging cycles",
|
||||
"arabic_name": "",
|
||||
"id_parent": 1631
|
||||
}
|
||||
}
|
||||
]
|
||||
BIN
carspecificationvalue_backup_015528012025.json
Normal file
955077
cartrim_backup_015528012025.json
Normal file
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-28 15:50
|
||||
# Generated by Django 5.1.5 on 2025-01-30 11:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-28 15:50
|
||||
# Generated by Django 5.1.5 on 2025-01-30 11:28
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
@ -9,6 +9,8 @@ from phonenumber_field.phonenumber import PhoneNumber
|
||||
from .mixins import AddClassMixin
|
||||
from django.forms.models import inlineformset_factory
|
||||
from django_ledger.forms.invoice import InvoiceModelCreateForm as InvoiceModelCreateFormBase
|
||||
from django_ledger.forms.estimate import EstimateModelCreateForm as EstimateModelCreateFormBase
|
||||
|
||||
from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase
|
||||
from django_ledger.forms.vendor import VendorModelForm
|
||||
from .models import (
|
||||
@ -68,21 +70,21 @@ class StaffForm(forms.ModelForm):
|
||||
model = Staff
|
||||
fields = ["name", "arabic_name", "phone_number", "staff_type"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user_instance = kwargs.get("instance")
|
||||
if user_instance and user_instance.user:
|
||||
initial = kwargs.setdefault("initial", {})
|
||||
initial["email"] = user_instance.user.email
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
user_instance = super().save(commit=False)
|
||||
user = user_instance.user
|
||||
user.email = self.cleaned_data["email"]
|
||||
if commit:
|
||||
user.save()
|
||||
user_instance.save()
|
||||
return user_instance
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# user_instance = kwargs.get("instance")
|
||||
# if user_instance and user_instance.user:
|
||||
# initial = kwargs.setdefault("initial", {})
|
||||
# initial["email"] = user_instance.user.email
|
||||
# super().__init__(*args, **kwargs)
|
||||
#
|
||||
# def save(self, commit=True):
|
||||
# user_instance = super().save(commit=False)
|
||||
# user = user_instance.user
|
||||
# user.email = self.cleaned_data["email"]
|
||||
# if commit:
|
||||
# user.save()
|
||||
# user_instance.save()
|
||||
# return user_instance
|
||||
|
||||
|
||||
# Dealer Form
|
||||
@ -676,6 +678,9 @@ class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
|
||||
self.fields['unearned_account'].widget = forms.HiddenInput()
|
||||
self.fields['date_draft'] = forms.DateField(widget=DateInput(attrs={'type': 'date'}))
|
||||
|
||||
def get_customer_queryset(self):
|
||||
if 'customer' in self.fields:
|
||||
self.fields['customer'].queryset = self.USER_MODEL.dealer.entity.get_customers()
|
||||
|
||||
class BillModelCreateForm(BillModelCreateFormBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -689,7 +694,18 @@ class BillModelCreateForm(BillModelCreateFormBase):
|
||||
class SaleOrderForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = SaleOrder
|
||||
fields = ['payment_method', 'comments']
|
||||
fields = ['estimate','payment_method', 'comments']
|
||||
widgets = {
|
||||
'comments': forms.Textarea(attrs={'rows': 3}),
|
||||
}
|
||||
}
|
||||
|
||||
class EstimateModelCreateForm(EstimateModelCreateFormBase):
|
||||
def __init__(self, *args, entity_slug, user_model, **kwargs):
|
||||
super(EstimateModelCreateForm, self).__init__(*args, entity_slug=entity_slug, user_model=user_model, **kwargs)
|
||||
self.ENTITY_SLUG = entity_slug
|
||||
self.USER_MODEL = user_model
|
||||
self.fields['customer'].queryset = self.get_customer_queryset()
|
||||
|
||||
def get_customer_queryset(self):
|
||||
return self.USER_MODEL.dealer.entity.get_customers()
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import logging
|
||||
from inventory import models
|
||||
from django.utils import timezone
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
|
||||
logger = logging.getLogger('user_activity')
|
||||
|
||||
@ -41,4 +43,14 @@ class InjectParamsMiddleware:
|
||||
|
||||
response = self.get_response(request)
|
||||
|
||||
return response
|
||||
return response
|
||||
|
||||
|
||||
# class OTPVerificationMiddleware:
|
||||
# def __init__(self, get_response):
|
||||
# self.get_response = get_response
|
||||
#
|
||||
# def __call__(self, request):
|
||||
# if request.user.is_authenticated and not request.session.get('otp_verified', False):
|
||||
# return redirect(reverse('verify_otp'))
|
||||
# return self.get_response(request)
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.5 on 2025-01-28 15:50
|
||||
# Generated by Django 5.1.5 on 2025-01-30 11:28
|
||||
|
||||
import django.db.models.deletion
|
||||
import inventory.mixins
|
||||
@ -546,9 +546,13 @@ class Migration(migrations.Migration):
|
||||
('payment_method', models.CharField(choices=[('cash', 'Cash'), ('finance', 'Finance'), ('lease', 'Lease')], max_length=20)),
|
||||
('comments', models.TextField(blank=True, null=True)),
|
||||
('formatted_order_id', models.CharField(editable=False, max_length=10, unique=True)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('estimate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL, verbose_name='Estimate')),
|
||||
('invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_INVOICE_MODEL, verbose_name='Invoice')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Staff',
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
# Generated by Django 4.2.17 on 2025-01-29 12:59
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0011_alter_saleorder_estimate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='saleorder',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@ -1,17 +0,0 @@
|
||||
# Generated by Django 4.2.17 on 2025-01-29 13:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0012_saleorder_created'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='saleorder',
|
||||
options={'ordering': ['created']},
|
||||
),
|
||||
]
|
||||
@ -689,10 +689,10 @@ def create_item_model(sender, instance, created, **kwargs):
|
||||
item_type=ItemModel.ITEM_TYPE_MATERIAL,
|
||||
uom_model=uom,
|
||||
coa_model=coa,
|
||||
|
||||
# additional_info={}
|
||||
)
|
||||
|
||||
product.additional_info = {}
|
||||
product.save()
|
||||
|
||||
product = entity.get_items_all().filter(name=instance.vin).first()
|
||||
product.additional_info.update({'car_info': instance.to_dict()})
|
||||
product.save()
|
||||
@ -703,6 +703,7 @@ def update_item_model_cost(sender, instance, created, **kwargs):
|
||||
entity = instance.car.dealer.entity
|
||||
|
||||
product = entity.get_items_all().filter(name=instance.car.vin).first()
|
||||
|
||||
product.default_amount = instance.selling_price
|
||||
product.additional_info = {}
|
||||
product.additional_info.update({"car_finance":instance.to_dict()})
|
||||
@ -864,3 +865,4 @@ def update_car_status_on_reservation_update(sender, instance, **kwargs):
|
||||
|
||||
# items = instance.get_itemtxs_data()[0].all()
|
||||
# total = sum([Decimal(item.item_model.additional_info['car_finance']["selling_price"]) * Decimal(item.ce_quantity) for item in items])
|
||||
|
||||
|
||||
@ -1,48 +1,45 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from allauth.account import views as allauth_views
|
||||
from django.conf.urls import handler400, handler403, handler404, handler500
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
# main URLs
|
||||
path("", views.HomeView.as_view(), name="landing_page"),
|
||||
path("", views.HomeView.as_view(), name="home"),
|
||||
path("welcome/", views.WelcomeView.as_view(), name="welcome"),
|
||||
# Accounts URLs
|
||||
path("login/", views.Login.as_view(), name="account_login"),
|
||||
path(
|
||||
"logout/",
|
||||
allauth_views.LogoutView.as_view(template_name="account/logout.html"),
|
||||
name="account_logout",
|
||||
),
|
||||
# path("login/", allauth_views.LoginView.as_view(template_name="account/login.html"), name="account_login"),
|
||||
# path(
|
||||
# "logout/",
|
||||
# allauth_views.LogoutView.as_view(template_name="account/logout.html"),
|
||||
# name="account_logout",
|
||||
# ),
|
||||
# path('signup/', allauth_views.SignupView.as_view(template_name='account/signup.html'), name='account_signup'),
|
||||
path("signup/", views.dealer_signup, name="account_signup"),
|
||||
path(
|
||||
"password/change/",
|
||||
allauth_views.PasswordChangeView.as_view(
|
||||
template_name="account/password_change.html"
|
||||
),
|
||||
name="account_change_password",
|
||||
),
|
||||
path(
|
||||
"password/reset/",
|
||||
allauth_views.PasswordResetView.as_view(
|
||||
template_name="account/password_reset.html"
|
||||
),
|
||||
name="account_reset_password",
|
||||
),
|
||||
path(
|
||||
"password/reset/done/",
|
||||
allauth_views.PasswordResetDoneView.as_view(
|
||||
template_name="account/password_reset_done.html"
|
||||
),
|
||||
name="account_password_reset_done",
|
||||
),
|
||||
path(
|
||||
"login/code/",
|
||||
allauth_views.RequestLoginCodeView.as_view(
|
||||
template_name="account/request_login_code.html"
|
||||
),
|
||||
),
|
||||
path("otp", views.OTPView.as_view(), name="otp"),
|
||||
# path(
|
||||
# "password/change/", allauth_views.PasswordChangeView.as_view(template_name="account/password_change.html"), name="account_change_password",
|
||||
# ),
|
||||
# path(
|
||||
# "password/reset/",
|
||||
# allauth_views.PasswordResetView.as_view(
|
||||
# template_name="account/password_reset.html"
|
||||
# ),
|
||||
# name="account_reset_password",
|
||||
# ),
|
||||
# path(
|
||||
# "accounts/password/reset/done/",
|
||||
# allauth_views.PasswordResetDoneView.as_view(
|
||||
# template_name="account/password_reset_done.html"
|
||||
# ),
|
||||
# name="account_password_reset_done",
|
||||
# ),
|
||||
# path(
|
||||
# "accounts/login/code/",
|
||||
# allauth_views.RequestLoginCodeView.as_view(
|
||||
# template_name="account/request_login_code.html"
|
||||
# ),
|
||||
# ),
|
||||
# Dashboards
|
||||
path(
|
||||
"dashboards/accounting/", views.AccountingDashboard.as_view(), name="accounting"
|
||||
@ -147,7 +144,7 @@ urlpatterns = [
|
||||
),
|
||||
# Vendor URLs
|
||||
path("vendors", views.VendorListView.as_view(), name="vendor_list"),
|
||||
path("vendors/<uuid:pk>/", views.VendorDetailView.as_view(), name="vendor_detail"),
|
||||
path("vendors/<uuid:pk>/", views.vendorDetailView, name="vendor_detail"),
|
||||
path("vendors/create/", views.VendorCreateView.as_view(), name="vendor_create"),
|
||||
path(
|
||||
"vendors/<uuid:pk>/update/",
|
||||
|
||||
@ -73,7 +73,11 @@ from django.urls import reverse, reverse_lazy
|
||||
from django.contrib import messages
|
||||
from django.db.models import Sum, F, Count
|
||||
from django.db import transaction
|
||||
from two_factor.utils import default_device
|
||||
|
||||
from two_factor.views import OTPRequiredMixin
|
||||
|
||||
from .forms import VendorForm
|
||||
from .services import (
|
||||
decodevin,
|
||||
get_make,
|
||||
@ -98,7 +102,7 @@ from .utils import (
|
||||
transfer_car,
|
||||
)
|
||||
from django.contrib.auth.models import User
|
||||
from allauth.account import views
|
||||
from allauth.account import views as allauth_views
|
||||
from django.db.models import Count, F, Value
|
||||
from django.contrib.auth import authenticate
|
||||
import cv2
|
||||
@ -107,6 +111,7 @@ from pyzbar.pyzbar import decode
|
||||
from django.core.files.storage import default_storage
|
||||
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
@ -183,13 +188,14 @@ def dealer_signup(request, *args, **kwargs):
|
||||
phone_number=phone,
|
||||
address=address,
|
||||
)
|
||||
user = authenticate(request, email=email, password=password)
|
||||
if user is not None:
|
||||
return JsonResponse(
|
||||
{"message": "User created successfully."}, status=200
|
||||
)
|
||||
else:
|
||||
return JsonResponse({"error": "User creation failed."}, status=400)
|
||||
# user = authenticate(request, email=email, password=password)
|
||||
# if user is not None:
|
||||
# return JsonResponse(
|
||||
# {"message": "User created successfully."}, status=200
|
||||
# )
|
||||
# else:
|
||||
# return JsonResponse({"error": "User creation failed."}, status=400)
|
||||
# return redirect("account_login")
|
||||
|
||||
except Exception as e:
|
||||
return JsonResponse({"error": str(e)}, status=400)
|
||||
@ -204,20 +210,41 @@ def dealer_signup(request, *args, **kwargs):
|
||||
)
|
||||
|
||||
|
||||
class Login(views.LoginView):
|
||||
template_name = "account/login.html"
|
||||
redirect_authenticated_user = True
|
||||
# class Login(allauth_views.LoginView):
|
||||
# template_name = "account/login.html"
|
||||
# redirect_authenticated_user = True
|
||||
class OTPView(View, LoginRequiredMixin):
|
||||
template_name = "account/otp_verification.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
# device = default_device(request.user)
|
||||
# device.generate_challenge()
|
||||
return render(request, self.template_name)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
otp_code = request.POST.get("otp_code")
|
||||
|
||||
if self.verify_otp(otp_code, request.user):
|
||||
messages.success(request, _("OTP verified successfully!"))
|
||||
return redirect("home")
|
||||
|
||||
messages.error(request, _("Invalid OTP. Please try again."))
|
||||
return render(request, self.template_name)
|
||||
|
||||
def verify_otp(self, otp_code, user):
|
||||
device = default_device(user)
|
||||
if device and device.verify_token(otp_code):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
class HomeView(TemplateView):
|
||||
template_name = "index.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if (
|
||||
# not any(hasattr(request.user, attr) for attr in ["dealer", "subdealer"])
|
||||
not request.user.is_authenticated
|
||||
):
|
||||
# messages.error(request, _("You are not associated with any dealer."))
|
||||
if not request.user.is_authenticated:
|
||||
return redirect("welcome")
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
@ -1204,13 +1231,17 @@ class VendorListView(LoginRequiredMixin, ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
dealer = get_user_type(self.request)
|
||||
|
||||
# vendors = models.Vendor.objects.filter(dealer=dealer)
|
||||
return dealer.entity.get_vendors().filter(active=True)
|
||||
# return vendors
|
||||
|
||||
|
||||
class VendorDetailView(LoginRequiredMixin, DetailView):
|
||||
model = VendorModel
|
||||
template_name = "vendors/view_vendor.html"
|
||||
# class VendorDetailView(LoginRequiredMixin, DetailView):
|
||||
# model = models.Vendor
|
||||
# template_name = "vendors/view_vendor.html"
|
||||
def vendorDetailView(request, pk):
|
||||
vendor = get_object_or_404(models.Vendor, pk=pk)
|
||||
return render(request, template_name="vendors/view_vendor.html", context={"vendor": vendor})
|
||||
|
||||
|
||||
class VendorCreateView(
|
||||
@ -1218,7 +1249,7 @@ class VendorCreateView(
|
||||
SuccessMessageMixin,
|
||||
CreateView,
|
||||
):
|
||||
model = VendorModel
|
||||
model = models.Vendor
|
||||
form_class = forms.VendorForm
|
||||
template_name = "vendors/vendor_form.html"
|
||||
success_url = reverse_lazy("vendor_list")
|
||||
@ -1226,9 +1257,10 @@ class VendorCreateView(
|
||||
|
||||
def form_valid(self, form):
|
||||
dealer = get_user_type(self.request)
|
||||
instance = form.save(commit=False)
|
||||
instance.entity_model = dealer.entity
|
||||
instance.save()
|
||||
form.instance.dealer = dealer
|
||||
# instance = form.save(commit=False)
|
||||
# instance.entity_model = dealer.entity
|
||||
form.instance.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
@ -1237,7 +1269,7 @@ class VendorUpdateView(
|
||||
SuccessMessageMixin,
|
||||
UpdateView,
|
||||
):
|
||||
model = VendorModel
|
||||
model = models.Vendor
|
||||
form_class = forms.VendorForm
|
||||
template_name = "vendors/vendor_form.html"
|
||||
success_url = reverse_lazy("vendor_list")
|
||||
@ -1246,149 +1278,149 @@ class VendorUpdateView(
|
||||
|
||||
@login_required
|
||||
def delete_vendor(request, pk):
|
||||
vendor = get_object_or_404(VendorModel, pk=pk)
|
||||
vendor.active = False
|
||||
vendor.save()
|
||||
vendor = get_object_or_404(models.Vendor, pk=pk)
|
||||
# vendor.active = False
|
||||
vendor.delete()
|
||||
messages.success(request, _("Vendor deleted successfully."))
|
||||
return redirect("vendor_list")
|
||||
|
||||
|
||||
class QuotationCreateView(LoginRequiredMixin, CreateView):
|
||||
model = models.SaleQuotation
|
||||
form_class = forms.QuotationForm
|
||||
template_name = "sales/quotation_form.html"
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.dealer = get_user_type(self.request)
|
||||
quotation = form.save()
|
||||
selected_cars = form.cleaned_data.get("cars")
|
||||
for car in selected_cars:
|
||||
car_finance = car.finances
|
||||
if car_finance:
|
||||
models.SaleQuotationCar.objects.create(
|
||||
quotation=quotation,
|
||||
car=car,
|
||||
)
|
||||
|
||||
messages.success(self.request, _("Quotation created successfully."))
|
||||
return redirect("quotation_list")
|
||||
# class QuotationCreateView(LoginRequiredMixin, CreateView):
|
||||
# model = models.SaleQuotation
|
||||
# form_class = forms.QuotationForm
|
||||
# template_name = "sales/quotation_form.html"
|
||||
#
|
||||
# def form_valid(self, form):
|
||||
# form.instance.dealer = get_user_type(self.request)
|
||||
# quotation = form.save()
|
||||
# selected_cars = form.cleaned_data.get("cars")
|
||||
# for car in selected_cars:
|
||||
# car_finance = car.finances
|
||||
# if car_finance:
|
||||
# models.SaleQuotationCar.objects.create(
|
||||
# quotation=quotation,
|
||||
# car=car,
|
||||
# )
|
||||
#
|
||||
# messages.success(self.request, _("Quotation created successfully."))
|
||||
# return redirect("quotation_list")
|
||||
|
||||
|
||||
class QuotationListView(LoginRequiredMixin, ListView):
|
||||
model = models.SaleQuotation
|
||||
template_name = "sales/quotation_list.html"
|
||||
context_object_name = "quotations"
|
||||
paginate_by = 10
|
||||
|
||||
def get_queryset(self):
|
||||
status = self.request.GET.get("status")
|
||||
dealer = get_user_type(self.request)
|
||||
queryset = dealer.sales.all()
|
||||
if status:
|
||||
queryset = queryset.filter(status=status)
|
||||
return queryset
|
||||
# class QuotationListView(LoginRequiredMixin, ListView):
|
||||
# model = models.SaleQuotation
|
||||
# template_name = "sales/quotation_list.html"
|
||||
# context_object_name = "quotations"
|
||||
# paginate_by = 10
|
||||
#
|
||||
# def get_queryset(self):
|
||||
# status = self.request.GET.get("status")
|
||||
# dealer = get_user_type(self.request)
|
||||
# queryset = dealer.sales.all()
|
||||
# if status:
|
||||
# queryset = queryset.filter(status=status)
|
||||
# return queryset
|
||||
|
||||
|
||||
class QuotationDetailView(LoginRequiredMixin, DetailView):
|
||||
model = models.SaleQuotation
|
||||
template_name = "sales/quotation_detail.html"
|
||||
context_object_name = "quotation"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
quotation = self.object
|
||||
|
||||
context_result = get_calculations(quotation)
|
||||
context.update(context_result)
|
||||
|
||||
return context
|
||||
# class QuotationDetailView(LoginRequiredMixin, DetailView):
|
||||
# model = models.SaleQuotation
|
||||
# template_name = "sales/quotation_detail.html"
|
||||
# context_object_name = "quotation"
|
||||
#
|
||||
# def get_context_data(self, **kwargs):
|
||||
# context = super().get_context_data(**kwargs)
|
||||
# quotation = self.object
|
||||
#
|
||||
# context_result = get_calculations(quotation)
|
||||
# context.update(context_result)
|
||||
#
|
||||
# return context
|
||||
|
||||
|
||||
@login_required
|
||||
def generate_invoice(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = get_user_type(request)
|
||||
entity = dealer.entity
|
||||
if not quotation.is_approved:
|
||||
messages.error(
|
||||
request, "Quotation must be approved before converting to an invoice."
|
||||
)
|
||||
else:
|
||||
coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
recivable_account = (
|
||||
coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
)
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=quotation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
|
||||
invoice_model = entity.create_invoice(
|
||||
customer_model=customer,
|
||||
terms=InvoiceModel.TERMS_ON_RECEIPT,
|
||||
cash_account=cash_account.first(),
|
||||
prepaid_account=recivable_account.first(),
|
||||
coa_model=coa_qs.first(),
|
||||
)
|
||||
|
||||
name_list = [
|
||||
f"{instance.car.year} {instance.car.id_car_make} {instance.car.id_car_model} {instance.car.id_car_trim}"
|
||||
for instance in quotation.quotation_cars.all()
|
||||
]
|
||||
|
||||
invoices_item_models = invoice_model.get_item_model_qs().filter(
|
||||
name__in=name_list
|
||||
)
|
||||
|
||||
invoice_itemtxs = {
|
||||
im.item_number: {
|
||||
"unit_cost": im.default_amount,
|
||||
"quantity": 1,
|
||||
"total_amount": im.default_amount,
|
||||
}
|
||||
for im in invoices_item_models
|
||||
}
|
||||
|
||||
invoice_itemtxs = invoice_model.migrate_itemtxs(
|
||||
itemtxs=invoice_itemtxs, commit=True, operation=InvoiceModel.ITEMIZE_APPEND
|
||||
)
|
||||
ledger = (
|
||||
entity.get_ledgers()
|
||||
.filter(name=f"Payment Ledger for Invoice {invoice_model}")
|
||||
.first()
|
||||
)
|
||||
if not ledger:
|
||||
ledger = entity.create_ledger(
|
||||
name=f"Payment Ledger for Invoice {invoice_model}", posted=True
|
||||
)
|
||||
journal_entry = JournalEntryModel.objects.create(
|
||||
posted=False,
|
||||
description=f"Payment for Invoice {invoice_model}",
|
||||
ledger=ledger,
|
||||
locked=False,
|
||||
origin="Payment",
|
||||
)
|
||||
|
||||
quotation.payment_id = journal_entry.pk
|
||||
quotation.is_approved = True
|
||||
date = datetime.datetime.now()
|
||||
quotation.date_draft = date
|
||||
invoice_model.date_draft = date
|
||||
invoice_model.save()
|
||||
quotation.save()
|
||||
|
||||
if not invoice_model.can_review():
|
||||
messages.error(request, "Quotation is not ready for review")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
invoice_model.mark_as_review()
|
||||
invoice_model.date_in_review = date
|
||||
quotation.date_in_review = date
|
||||
quotation.status = "In Review"
|
||||
invoice_model.save()
|
||||
quotation.save()
|
||||
# @login_required
|
||||
# def generate_invoice(request, pk):
|
||||
# quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# dealer = get_user_type(request)
|
||||
# entity = dealer.entity
|
||||
# if not quotation.is_approved:
|
||||
# messages.error(
|
||||
# request, "Quotation must be approved before converting to an invoice."
|
||||
# )
|
||||
# else:
|
||||
# coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
# cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
# recivable_account = (
|
||||
# coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
# )
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=quotation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
#
|
||||
# invoice_model = entity.create_invoice(
|
||||
# customer_model=customer,
|
||||
# terms=InvoiceModel.TERMS_ON_RECEIPT,
|
||||
# cash_account=cash_account.first(),
|
||||
# prepaid_account=recivable_account.first(),
|
||||
# coa_model=coa_qs.first(),
|
||||
# )
|
||||
#
|
||||
# name_list = [
|
||||
# f"{instance.car.year} {instance.car.id_car_make} {instance.car.id_car_model} {instance.car.id_car_trim}"
|
||||
# for instance in quotation.quotation_cars.all()
|
||||
# ]
|
||||
#
|
||||
# invoices_item_models = invoice_model.get_item_model_qs().filter(
|
||||
# name__in=name_list
|
||||
# )
|
||||
#
|
||||
# invoice_itemtxs = {
|
||||
# im.item_number: {
|
||||
# "unit_cost": im.default_amount,
|
||||
# "quantity": 1,
|
||||
# "total_amount": im.default_amount,
|
||||
# }
|
||||
# for im in invoices_item_models
|
||||
# }
|
||||
#
|
||||
# invoice_itemtxs = invoice_model.migrate_itemtxs(
|
||||
# itemtxs=invoice_itemtxs, commit=True, operation=InvoiceModel.ITEMIZE_APPEND
|
||||
# )
|
||||
# ledger = (
|
||||
# entity.get_ledgers()
|
||||
# .filter(name=f"Payment Ledger for Invoice {invoice_model}")
|
||||
# .first()
|
||||
# )
|
||||
# if not ledger:
|
||||
# ledger = entity.create_ledger(
|
||||
# name=f"Payment Ledger for Invoice {invoice_model}", posted=True
|
||||
# )
|
||||
# journal_entry = JournalEntryModel.objects.create(
|
||||
# posted=False,
|
||||
# description=f"Payment for Invoice {invoice_model}",
|
||||
# ledger=ledger,
|
||||
# locked=False,
|
||||
# origin="Payment",
|
||||
# )
|
||||
#
|
||||
# quotation.payment_id = journal_entry.pk
|
||||
# quotation.is_approved = True
|
||||
# date = datetime.datetime.now()
|
||||
# quotation.date_draft = date
|
||||
# invoice_model.date_draft = date
|
||||
# invoice_model.save()
|
||||
# quotation.save()
|
||||
#
|
||||
# if not invoice_model.can_review():
|
||||
# messages.error(request, "Quotation is not ready for review")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# invoice_model.mark_as_review()
|
||||
# invoice_model.date_in_review = date
|
||||
# quotation.date_in_review = date
|
||||
# quotation.status = "In Review"
|
||||
# invoice_model.save()
|
||||
# quotation.save()
|
||||
|
||||
# elif status == "approved":
|
||||
# if qoutation.status == "Approved":
|
||||
@ -1460,41 +1492,41 @@ def generate_invoice(request, pk):
|
||||
# invoice_model.mark_as_paid(entity_slug=entity.slug, user_model=request.user.dealer.get_root_dealer.user)
|
||||
# print("paid")
|
||||
# invoice_model.save()
|
||||
messages.success(request, "Invoice created")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
# messages.success(request, "Invoice created")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
# return redirect('django_ledger:invoice-detail', entity_slug=quotation.entity.slug, invoice_pk=invoice.uuid)
|
||||
|
||||
|
||||
@login_required
|
||||
def post_quotation(request, pk):
|
||||
qoutation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = get_user_type(request)
|
||||
entity = dealer.entity
|
||||
if qoutation.posted:
|
||||
messages.error(request, "Quotation is already posted")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
recivable_account = (
|
||||
coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
)
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=qoutation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
invoice_model = (
|
||||
entity.get_invoices()
|
||||
.filter(customer=customer, date_paid=qoutation.date_paid)
|
||||
.first()
|
||||
)
|
||||
ledger = (
|
||||
entity.get_ledgers()
|
||||
.filter(name=f"Payment Ledger for Invoice {invoice_model}")
|
||||
.first()
|
||||
)
|
||||
return
|
||||
# @login_required
|
||||
# def post_quotation(request, pk):
|
||||
# qoutation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# dealer = get_user_type(request)
|
||||
# entity = dealer.entity
|
||||
# if qoutation.posted:
|
||||
# messages.error(request, "Quotation is already posted")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
# coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
# cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
# recivable_account = (
|
||||
# coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
# )
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=qoutation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
# invoice_model = (
|
||||
# entity.get_invoices()
|
||||
# .filter(customer=customer, date_paid=qoutation.date_paid)
|
||||
# .first()
|
||||
# )
|
||||
# ledger = (
|
||||
# entity.get_ledgers()
|
||||
# .filter(name=f"Payment Ledger for Invoice {invoice_model}")
|
||||
# .first()
|
||||
# )
|
||||
# return
|
||||
# if not ledger:
|
||||
# ledger = entity.create_ledger(name=f"Payment Ledger for Invoice {invoice_model}",posted=True)
|
||||
|
||||
@ -1536,98 +1568,98 @@ def post_quotation(request, pk):
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
|
||||
@login_required
|
||||
def mark_quotation(request, pk):
|
||||
qoutation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
status = request.GET.get("status")
|
||||
dealer = request.user.dealer
|
||||
entity = dealer.entity
|
||||
date = datetime.datetime.now()
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=qoutation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
invoice_model = entity.get_invoices().filter(customer=customer)
|
||||
if status == "approved":
|
||||
if qoutation.status == "Approved":
|
||||
messages.error(request, "Quotation is already approved")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
invoice_model = invoice_model.filter(
|
||||
date_in_review=qoutation.date_in_review
|
||||
).first()
|
||||
if not invoice_model.can_approve():
|
||||
messages.error(request, "Quotation is not ready for approval")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
invoice_model.mark_as_approved(
|
||||
entity_slug=entity.slug, user_model=request.user.dealer
|
||||
)
|
||||
invoice_model.date_approved = date
|
||||
qoutation.date_approved = date
|
||||
invoice_model.save()
|
||||
qoutation.status = "Approved"
|
||||
qoutation.save()
|
||||
for car in qoutation.quotation_cars.all():
|
||||
car.car.status = "reserved"
|
||||
car.car.save()
|
||||
messages.success(request, _("Quotation Approved"))
|
||||
elif status == "paid":
|
||||
if qoutation.status == "Paid":
|
||||
messages.error(request, "Quotation is already paid")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
invoice_model = invoice_model.filter(
|
||||
date_approved=qoutation.date_approved
|
||||
).first()
|
||||
if not invoice_model.can_pay():
|
||||
messages.error(request, "Quotation is not ready for payment")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
invoice_model.mark_as_paid(
|
||||
entity_slug=entity.slug, user_model=request.user.dealer
|
||||
)
|
||||
invoice_model.date_paid = date
|
||||
qoutation.date_paid = date
|
||||
invoice_model.save()
|
||||
qoutation.status = "Paid"
|
||||
qoutation.save()
|
||||
messages.success(request, _("Quotation Paid"))
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
# @login_required
|
||||
# def mark_quotation(request, pk):
|
||||
# qoutation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# status = request.GET.get("status")
|
||||
# dealer = request.user.dealer
|
||||
# entity = dealer.entity
|
||||
# date = datetime.datetime.now()
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=qoutation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
# invoice_model = entity.get_invoices().filter(customer=customer)
|
||||
# if status == "approved":
|
||||
# if qoutation.status == "Approved":
|
||||
# messages.error(request, "Quotation is already approved")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# invoice_model = invoice_model.filter(
|
||||
# date_in_review=qoutation.date_in_review
|
||||
# ).first()
|
||||
# if not invoice_model.can_approve():
|
||||
# messages.error(request, "Quotation is not ready for approval")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# invoice_model.mark_as_approved(
|
||||
# entity_slug=entity.slug, user_model=request.user.dealer
|
||||
# )
|
||||
# invoice_model.date_approved = date
|
||||
# qoutation.date_approved = date
|
||||
# invoice_model.save()
|
||||
# qoutation.status = "Approved"
|
||||
# qoutation.save()
|
||||
# for car in qoutation.quotation_cars.all():
|
||||
# car.car.status = "reserved"
|
||||
# car.car.save()
|
||||
# messages.success(request, _("Quotation Approved"))
|
||||
# elif status == "paid":
|
||||
# if qoutation.status == "Paid":
|
||||
# messages.error(request, "Quotation is already paid")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# invoice_model = invoice_model.filter(
|
||||
# date_approved=qoutation.date_approved
|
||||
# ).first()
|
||||
# if not invoice_model.can_pay():
|
||||
# messages.error(request, "Quotation is not ready for payment")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# invoice_model.mark_as_paid(
|
||||
# entity_slug=entity.slug, user_model=request.user.dealer
|
||||
# )
|
||||
# invoice_model.date_paid = date
|
||||
# qoutation.date_paid = date
|
||||
# invoice_model.save()
|
||||
# qoutation.status = "Paid"
|
||||
# qoutation.save()
|
||||
# messages.success(request, _("Quotation Paid"))
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
|
||||
@login_required
|
||||
def confirm_quotation(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
if quotation.is_approved:
|
||||
messages.error(request, _("Quotation already approved."))
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
# @login_required
|
||||
# def confirm_quotation(request, pk):
|
||||
# quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# if quotation.is_approved:
|
||||
# messages.error(request, _("Quotation already approved."))
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
#
|
||||
# try:
|
||||
# # quotation.confirm()
|
||||
# # quotation_cars = quotation.quotation_cars.annotate(total_price=F('car__total') * F('quantity'))
|
||||
# # total = quotation.quotation_cars.aggregate(total_price=Sum(F('car__finances__selling_price') * F('quantity')))
|
||||
#
|
||||
# models.SalesOrder.objects.create(
|
||||
# quotation=quotation,
|
||||
# total_amount=quotation.total_vat,
|
||||
# # total_amount=quotation.quotation_cars.aggregate(Sum("total_amount"))["total_amount__sum"],
|
||||
# )
|
||||
# quotation.is_approved = True
|
||||
# quotation.save()
|
||||
# messages.success(request, _("Quotation confirmed and sales order created."))
|
||||
# except ValueError as e:
|
||||
# messages.error(request, str(e))
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
try:
|
||||
# quotation.confirm()
|
||||
# quotation_cars = quotation.quotation_cars.annotate(total_price=F('car__total') * F('quantity'))
|
||||
# total = quotation.quotation_cars.aggregate(total_price=Sum(F('car__finances__selling_price') * F('quantity')))
|
||||
|
||||
models.SalesOrder.objects.create(
|
||||
quotation=quotation,
|
||||
total_amount=quotation.total_vat,
|
||||
# total_amount=quotation.quotation_cars.aggregate(Sum("total_amount"))["total_amount__sum"],
|
||||
)
|
||||
quotation.is_approved = True
|
||||
quotation.save()
|
||||
messages.success(request, _("Quotation confirmed and sales order created."))
|
||||
except ValueError as e:
|
||||
messages.error(request, str(e))
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
|
||||
|
||||
class SalesOrderDetailView(LoginRequiredMixin, DetailView):
|
||||
model = models.SalesOrder
|
||||
template_name = "sales/sales_order_detail.html"
|
||||
context_object_name = "sales_order"
|
||||
slug_field = "order_id"
|
||||
slug_url_kwarg = "order_id"
|
||||
#
|
||||
# class SalesOrderDetailView(LoginRequiredMixin, DetailView):
|
||||
# model = models.SalesOrder
|
||||
# template_name = "sales/sales_order_detail.html"
|
||||
# context_object_name = "sales_order"
|
||||
# slug_field = "order_id"
|
||||
# slug_url_kwarg = "order_id"
|
||||
|
||||
|
||||
# Users
|
||||
@ -1875,64 +1907,64 @@ class RepresentativeDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteVi
|
||||
# return HttpResponse(pdf_file, content_type="application/pdf")
|
||||
|
||||
|
||||
@login_required
|
||||
def download_quotation_pdf(request, quotation_id):
|
||||
try:
|
||||
# Retrieve the quotation object
|
||||
quotation = models.SaleQuotation.objects.get(id=quotation_id)
|
||||
cars = models.SaleQuotationCar.objects.get(id=quotation_id)
|
||||
print(cars)
|
||||
services = cars.finance.additional_services.all()
|
||||
print(services)
|
||||
|
||||
# Create a response object
|
||||
response = HttpResponse(content_type="application/pdf")
|
||||
response["Content-Disposition"] = (
|
||||
f'attachment; filename="quotation_{quotation.id}.pdf"'
|
||||
)
|
||||
|
||||
# Call the PDF generation function
|
||||
# generate_quotation_pdf(response, quotation, services)
|
||||
|
||||
return response
|
||||
except models.SaleQuotation.DoesNotExist:
|
||||
return HttpResponse("Quotation not found", status=404)
|
||||
# @login_required
|
||||
# def download_quotation_pdf(request, quotation_id):
|
||||
# try:
|
||||
# # Retrieve the quotation object
|
||||
# quotation = models.SaleQuotation.objects.get(id=quotation_id)
|
||||
# cars = models.SaleQuotationCar.objects.get(id=quotation_id)
|
||||
# print(cars)
|
||||
# services = cars.finance.additional_services.all()
|
||||
# print(services)
|
||||
#
|
||||
# # Create a response object
|
||||
# response = HttpResponse(content_type="application/pdf")
|
||||
# response["Content-Disposition"] = (
|
||||
# f'attachment; filename="quotation_{quotation.id}.pdf"'
|
||||
# )
|
||||
#
|
||||
# # Call the PDF generation function
|
||||
# # generate_quotation_pdf(response, quotation, services)
|
||||
#
|
||||
# return response
|
||||
# except models.SaleQuotation.DoesNotExist:
|
||||
# return HttpResponse("Quotation not found", status=404)
|
||||
|
||||
|
||||
@login_required
|
||||
def invoice_detail(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = request.user.dealer
|
||||
entity = dealer.entity
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=quotation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
invoice_model = entity.get_invoices()
|
||||
|
||||
invoice = invoice_model.filter(
|
||||
customer=customer, date_draft=quotation.date_draft
|
||||
).first()
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
# @login_required
|
||||
# def invoice_detail(request, pk):
|
||||
# quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# dealer = request.user.dealer
|
||||
# entity = dealer.entity
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=quotation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
# invoice_model = entity.get_invoices()
|
||||
#
|
||||
# invoice = invoice_model.filter(
|
||||
# customer=customer, date_draft=quotation.date_draft
|
||||
# ).first()
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
|
||||
@login_required
|
||||
def payment_invoice(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = request.user.dealer
|
||||
entity = dealer.entity
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=quotation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
invoice_model = entity.get_invoices()
|
||||
invoice = invoice_model.filter(
|
||||
customer=customer, date_draft=quotation.date_draft
|
||||
).first()
|
||||
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
# @login_required
|
||||
# def payment_invoice(request, pk):
|
||||
# quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# dealer = request.user.dealer
|
||||
# entity = dealer.entity
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=quotation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
# invoice_model = entity.get_invoices()
|
||||
# invoice = invoice_model.filter(
|
||||
# customer=customer, date_draft=quotation.date_draft
|
||||
# ).first()
|
||||
#
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
|
||||
|
||||
# class PaymentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
|
||||
@ -1953,75 +1985,75 @@ def payment_invoice(request, pk):
|
||||
# return context
|
||||
|
||||
|
||||
def payment_create(request, pk):
|
||||
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
dealer = get_user_type(request)
|
||||
if request.method == "POST":
|
||||
form = forms.PaymentForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.instance.quotation = quotation
|
||||
insatnce = form.save()
|
||||
|
||||
dealer = dealer
|
||||
entity = dealer.entity
|
||||
customer = (
|
||||
entity.get_customers()
|
||||
.filter(customer_name=quotation.customer.get_full_name)
|
||||
.first()
|
||||
)
|
||||
coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
recivable_account = (
|
||||
coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
)
|
||||
journal_entry = JournalEntryModel.objects.filter(
|
||||
pk=quotation.payment_id
|
||||
).first()
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal_entry,
|
||||
account=cash_account.first(), # Debit Cash
|
||||
amount=insatnce.amount, # Payment amount
|
||||
tx_type="debit",
|
||||
description="Payment Received",
|
||||
)
|
||||
|
||||
TransactionModel.objects.create(
|
||||
journal_entry=journal_entry,
|
||||
account=recivable_account.first(), # Credit Accounts Receivable
|
||||
amount=insatnce.amount, # Payment amount
|
||||
tx_type="credit",
|
||||
description="Payment Received",
|
||||
)
|
||||
journal_entry.posted = True
|
||||
quotation.posted = True
|
||||
quotation.save()
|
||||
journal_entry.save()
|
||||
|
||||
invoice_model = (
|
||||
entity.get_invoices()
|
||||
.filter(date_approved=quotation.date_approved)
|
||||
.first()
|
||||
)
|
||||
|
||||
invoice_model.mark_as_paid(
|
||||
entity_slug=entity.slug, user_model=request.user.dealer
|
||||
)
|
||||
date = timezone.now()
|
||||
invoice_model.date_paid = date
|
||||
quotation.date_paid = date
|
||||
invoice_model.save()
|
||||
quotation.status = "Paid"
|
||||
quotation.save()
|
||||
|
||||
messages.success(request, "Payment created successfully.")
|
||||
return redirect("quotation_detail", pk=pk)
|
||||
else:
|
||||
form = forms.PaymentForm()
|
||||
return render(
|
||||
request,
|
||||
"sales/payments/payment_create.html",
|
||||
{"quotation": quotation, "form": form},
|
||||
)
|
||||
# def payment_create(request, pk):
|
||||
# quotation = get_object_or_404(models.SaleQuotation, pk=pk)
|
||||
# dealer = get_user_type(request)
|
||||
# if request.method == "POST":
|
||||
# form = forms.PaymentForm(request.POST)
|
||||
# if form.is_valid():
|
||||
# form.instance.quotation = quotation
|
||||
# insatnce = form.save()
|
||||
#
|
||||
# dealer = dealer
|
||||
# entity = dealer.entity
|
||||
# customer = (
|
||||
# entity.get_customers()
|
||||
# .filter(customer_name=quotation.customer.get_full_name)
|
||||
# .first()
|
||||
# )
|
||||
# coa_qs, coa_map = entity.get_all_coa_accounts()
|
||||
# cash_account = coa_qs.first().get_coa_accounts().filter(name="Cash")
|
||||
# recivable_account = (
|
||||
# coa_qs.first().get_coa_accounts().filter(name="Accounts Receivable")
|
||||
# )
|
||||
# journal_entry = JournalEntryModel.objects.filter(
|
||||
# pk=quotation.payment_id
|
||||
# ).first()
|
||||
# TransactionModel.objects.create(
|
||||
# journal_entry=journal_entry,
|
||||
# account=cash_account.first(), # Debit Cash
|
||||
# amount=insatnce.amount, # Payment amount
|
||||
# tx_type="debit",
|
||||
# description="Payment Received",
|
||||
# )
|
||||
#
|
||||
# TransactionModel.objects.create(
|
||||
# journal_entry=journal_entry,
|
||||
# account=recivable_account.first(), # Credit Accounts Receivable
|
||||
# amount=insatnce.amount, # Payment amount
|
||||
# tx_type="credit",
|
||||
# description="Payment Received",
|
||||
# )
|
||||
# journal_entry.posted = True
|
||||
# quotation.posted = True
|
||||
# quotation.save()
|
||||
# journal_entry.save()
|
||||
#
|
||||
# invoice_model = (
|
||||
# entity.get_invoices()
|
||||
# .filter(date_approved=quotation.date_approved)
|
||||
# .first()
|
||||
# )
|
||||
#
|
||||
# invoice_model.mark_as_paid(
|
||||
# entity_slug=entity.slug, user_model=request.user.dealer
|
||||
# )
|
||||
# date = timezone.now()
|
||||
# invoice_model.date_paid = date
|
||||
# quotation.date_paid = date
|
||||
# invoice_model.save()
|
||||
# quotation.status = "Paid"
|
||||
# quotation.save()
|
||||
#
|
||||
# messages.success(request, "Payment created successfully.")
|
||||
# return redirect("quotation_detail", pk=pk)
|
||||
# else:
|
||||
# form = forms.PaymentForm()
|
||||
# return render(
|
||||
# request,
|
||||
# "sales/payments/payment_create.html",
|
||||
# {"quotation": quotation, "form": form},
|
||||
# )
|
||||
|
||||
|
||||
# Ledger
|
||||
|
||||
506
requirements.txt
@ -1,252 +1,254 @@
|
||||
aiohappyeyeballs
|
||||
aiohttp
|
||||
aiohttp-retry
|
||||
aiosignal
|
||||
alabaster
|
||||
albucore
|
||||
albumentations
|
||||
annotated-types
|
||||
anyio
|
||||
arabic-reshaper
|
||||
asgiref
|
||||
astor
|
||||
astroid
|
||||
attrs
|
||||
autopep8
|
||||
Babel
|
||||
beautifulsoup4
|
||||
bleach
|
||||
blinker
|
||||
Brotli
|
||||
certifi
|
||||
cffi
|
||||
chardet
|
||||
charset-normalizer
|
||||
click
|
||||
colorama
|
||||
commonmark
|
||||
contourpy
|
||||
crispy-bootstrap5
|
||||
cryptography
|
||||
cssselect2
|
||||
ctranslate2
|
||||
cycler
|
||||
Cython
|
||||
decorator
|
||||
desert
|
||||
dill
|
||||
distro
|
||||
dj-rest-auth
|
||||
dj-shop-cart
|
||||
Django
|
||||
django-allauth
|
||||
django-appointment
|
||||
django-autoslug
|
||||
django-bootstrap5
|
||||
django-classy-tags
|
||||
django-cors-headers
|
||||
django-countries
|
||||
django-crispy-forms
|
||||
django-debug-toolbar
|
||||
django-extensions
|
||||
django-filter
|
||||
django-formtools
|
||||
django-ledger
|
||||
django-money
|
||||
django-next-url-mixin
|
||||
django-nine
|
||||
django-nonefield
|
||||
django-ordered-model
|
||||
django-phonenumber-field
|
||||
django-picklefield
|
||||
django-plans
|
||||
django-prometheus
|
||||
django-q2
|
||||
django-sekizai
|
||||
django-sequences
|
||||
django-silk
|
||||
django-sms
|
||||
django-sslserver
|
||||
django-tables2
|
||||
django-treebeard
|
||||
django-view-breadcrumbs
|
||||
djangocms-admin-style
|
||||
djangorestframework
|
||||
djangorestframework_simplejwt
|
||||
djangoviz
|
||||
docutils
|
||||
easy-thumbnails
|
||||
emoji
|
||||
et_xmlfile
|
||||
Faker
|
||||
filelock
|
||||
fire
|
||||
Flask
|
||||
fonttools
|
||||
frozenlist
|
||||
fsspec
|
||||
gprof2dot
|
||||
graphqlclient
|
||||
greenlet
|
||||
h11
|
||||
h2
|
||||
hpack
|
||||
hstspreload
|
||||
httpcore
|
||||
httpx
|
||||
hyperframe
|
||||
idna
|
||||
imageio
|
||||
imagesize
|
||||
imgaug
|
||||
iso4217
|
||||
isodate
|
||||
isort
|
||||
itsdangerous
|
||||
Jinja2
|
||||
jiter
|
||||
joblib
|
||||
kiwisolver
|
||||
lazy_loader
|
||||
ledger
|
||||
libretranslatepy
|
||||
lmdb
|
||||
lxml
|
||||
Markdown
|
||||
markdown-it-py
|
||||
MarkupSafe
|
||||
marshmallow
|
||||
matplotlib
|
||||
mccabe
|
||||
mdurl
|
||||
MouseInfo
|
||||
mpmath
|
||||
multidict
|
||||
mypy-extensions
|
||||
networkx
|
||||
newrelic
|
||||
nltk
|
||||
numpy
|
||||
oauthlib
|
||||
ofxtools
|
||||
openai
|
||||
opencv-contrib-python
|
||||
opencv-python
|
||||
opencv-python-headless
|
||||
openpyxl
|
||||
opt_einsum
|
||||
outcome
|
||||
packaging
|
||||
pandas
|
||||
pango
|
||||
pdfkit
|
||||
phonenumbers
|
||||
pillow
|
||||
platformdirs
|
||||
prometheus_client
|
||||
propcache
|
||||
protobuf
|
||||
psycopg
|
||||
psycopg-binary
|
||||
psycopg-c
|
||||
py-moneyed
|
||||
PyAutoGUI
|
||||
pyclipper
|
||||
pycodestyle
|
||||
pycparser
|
||||
pydantic
|
||||
pydantic_core
|
||||
pydotplus
|
||||
pydyf
|
||||
PyGetWindow
|
||||
Pygments
|
||||
PyJWT
|
||||
pylint
|
||||
PyMsgBox
|
||||
PyMySQL
|
||||
pyobjc-core
|
||||
pyobjc-framework-Cocoa
|
||||
pyobjc-framework-Quartz
|
||||
pyparsing
|
||||
pyperclip
|
||||
pyphen
|
||||
pypng
|
||||
PyRect
|
||||
PyScreeze
|
||||
pyserial
|
||||
PySocks
|
||||
python-bidi
|
||||
python-dateutil
|
||||
python-docx
|
||||
python-openid
|
||||
python-stdnum
|
||||
python3-saml
|
||||
pytweening
|
||||
pytz
|
||||
pyvin
|
||||
pywa
|
||||
pywhat
|
||||
pywhatkit
|
||||
PyYAML
|
||||
pyzbar
|
||||
qrcode
|
||||
RapidFuzz
|
||||
regex
|
||||
reportlab
|
||||
requests
|
||||
requests-oauthlib
|
||||
rfc3986
|
||||
rich
|
||||
rubicon-objc
|
||||
sacremoses
|
||||
scikit-image
|
||||
scikit-learn
|
||||
scipy
|
||||
selenium
|
||||
sentencepiece
|
||||
shapely
|
||||
simsimd
|
||||
six
|
||||
sniffio
|
||||
snowballstemmer
|
||||
sortedcontainers
|
||||
soupsieve
|
||||
SQLAlchemy
|
||||
sqlparse
|
||||
stanza
|
||||
stringzilla
|
||||
suds
|
||||
swapper
|
||||
sympy
|
||||
tablib
|
||||
termcolor
|
||||
threadpoolctl
|
||||
tifffile
|
||||
tinycss2
|
||||
tinyhtml5
|
||||
tomli
|
||||
tomlkit
|
||||
torch
|
||||
tqdm
|
||||
trio
|
||||
trio-websocket
|
||||
twilio
|
||||
typing-inspect
|
||||
typing_extensions
|
||||
tzdata
|
||||
Unidecode
|
||||
upgrade-requirements
|
||||
urllib3
|
||||
vin
|
||||
vininfo
|
||||
vishap
|
||||
vpic-api
|
||||
weasyprint
|
||||
webencodings
|
||||
websocket-client
|
||||
Werkzeug
|
||||
wikipedia
|
||||
wsproto
|
||||
xmlsec
|
||||
yarl
|
||||
zopfli
|
||||
aiohappyeyeballs==2.4.4
|
||||
aiohttp==3.11.11
|
||||
aiohttp-retry==2.9.1
|
||||
aiosignal==1.3.2
|
||||
alabaster==1.0.0
|
||||
albucore==0.0.23
|
||||
albumentations==2.0.2
|
||||
annotated-types==0.7.0
|
||||
anyio==4.8.0
|
||||
arabic-reshaper==3.0.0
|
||||
asgiref==3.8.1
|
||||
astor==0.8.1
|
||||
astroid==3.3.8
|
||||
attrs==23.2.0
|
||||
autopep8==2.3.2
|
||||
Babel==2.15.0
|
||||
beautifulsoup4==4.12.3
|
||||
bleach==6.2.0
|
||||
blinker==1.9.0
|
||||
Brotli==1.1.0
|
||||
certifi==2024.12.14
|
||||
cffi==1.17.1
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.4.1
|
||||
click==8.1.8
|
||||
colorama==0.4.6
|
||||
commonmark==0.9.1
|
||||
contourpy==1.3.1
|
||||
crispy-bootstrap5==2024.10
|
||||
cryptography==44.0.0
|
||||
cssselect2==0.7.0
|
||||
ctranslate2==4.5.0
|
||||
cycler==0.12.1
|
||||
Cython==3.1.0a1
|
||||
decorator==5.1.1
|
||||
desert==2020.11.18
|
||||
dill==0.3.9
|
||||
distro==1.9.0
|
||||
dj-rest-auth==7.0.1
|
||||
dj-shop-cart==8.0.0a2
|
||||
Django==5.1.5
|
||||
django-allauth==65.3.1
|
||||
django-appointment==3.7.4
|
||||
django-autoslug==1.9.9
|
||||
django-bootstrap5==24.3
|
||||
django-classy-tags==4.1.0
|
||||
django-cors-headers==4.6.0
|
||||
django-countries==7.6.1
|
||||
django-crispy-forms==2.3
|
||||
django-debug-toolbar==5.0.1
|
||||
django-extensions==3.2.3
|
||||
django-filter==24.3
|
||||
django-formtools==2.5.1
|
||||
django-ledger==0.7.3
|
||||
django-money==3.5.3
|
||||
django-next-url-mixin==0.4.0
|
||||
django-nine==0.2.7
|
||||
django-nonefield==0.4
|
||||
django-ordered-model==3.7.4
|
||||
django-otp==1.5.4
|
||||
django-phonenumber-field==8.0.0
|
||||
django-picklefield==3.2
|
||||
django-plans==1.2.0
|
||||
django-prometheus==2.3.1
|
||||
django-q2==1.7.6
|
||||
django-sekizai==4.1.0
|
||||
django-sequences==3.0
|
||||
django-silk==5.3.2
|
||||
django-sms==0.7.0
|
||||
django-sslserver==0.22
|
||||
django-tables2==2.7.5
|
||||
django-treebeard==4.7.1
|
||||
django-two-factor-auth==1.17.0
|
||||
django-view-breadcrumbs==2.5.1
|
||||
djangocms-admin-style==3.3.1
|
||||
djangorestframework==3.15.2
|
||||
djangorestframework_simplejwt==5.4.0
|
||||
djangoviz==0.1.1
|
||||
docutils==0.21.2
|
||||
easy-thumbnails==2.10
|
||||
emoji==2.14.1
|
||||
et_xmlfile==2.0.0
|
||||
Faker==35.0.0
|
||||
filelock==3.17.0
|
||||
fire==0.7.0
|
||||
Flask==3.1.0
|
||||
fonttools==4.55.7
|
||||
frozenlist==1.5.0
|
||||
fsspec==2024.12.0
|
||||
gprof2dot==2024.6.6
|
||||
graphqlclient==0.2.4
|
||||
greenlet==3.1.1
|
||||
h11==0.14.0
|
||||
h2==4.1.0
|
||||
hpack==4.1.0
|
||||
hstspreload==2025.1.1
|
||||
httpcore==1.0.7
|
||||
httpx==0.28.1
|
||||
hyperframe==6.1.0
|
||||
idna==3.10
|
||||
imageio==2.37.0
|
||||
imagesize==1.4.1
|
||||
imgaug==0.4.0
|
||||
iso4217==1.12.20240625
|
||||
isodate==0.7.2
|
||||
isort==6.0.0
|
||||
itsdangerous==2.2.0
|
||||
Jinja2==3.1.5
|
||||
jiter==0.8.2
|
||||
joblib==1.4.2
|
||||
kiwisolver==1.4.8
|
||||
lazy_loader==0.4
|
||||
ledger==1.0.1
|
||||
libretranslatepy==2.1.4
|
||||
lmdb==1.6.2
|
||||
lxml==5.3.0
|
||||
Markdown==3.7
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==3.0.2
|
||||
marshmallow==3.26.0
|
||||
matplotlib==3.10.0
|
||||
mccabe==0.7.0
|
||||
mdurl==0.1.2
|
||||
MouseInfo==0.1.3
|
||||
mpmath==1.3.0
|
||||
multidict==6.1.0
|
||||
mypy-extensions==1.0.0
|
||||
networkx==3.4.2
|
||||
newrelic==10.4.0
|
||||
nltk==3.9.1
|
||||
numpy==2.2.2
|
||||
oauthlib==3.2.2
|
||||
ofxtools==0.9.5
|
||||
openai==1.60.2
|
||||
opencv-contrib-python==4.11.0.86
|
||||
opencv-python==4.11.0.86
|
||||
opencv-python-headless==4.11.0.86
|
||||
openpyxl==3.1.5
|
||||
opt_einsum==3.4.0
|
||||
outcome==1.3.0.post0
|
||||
packaging==24.2
|
||||
pandas==2.2.3
|
||||
pango==0.0.1
|
||||
pdfkit==1.0.0
|
||||
phonenumbers==8.13.42
|
||||
pillow==10.4.0
|
||||
platformdirs==4.3.6
|
||||
prometheus_client==0.21.1
|
||||
propcache==0.2.1
|
||||
protobuf==5.29.3
|
||||
psycopg==3.2.4
|
||||
psycopg-binary==3.2.4
|
||||
psycopg-c==3.2.4
|
||||
py-moneyed==3.0
|
||||
PyAutoGUI==0.9.54
|
||||
pyclipper==1.3.0.post6
|
||||
pycodestyle==2.12.1
|
||||
pycparser==2.22
|
||||
pydantic==2.10.6
|
||||
pydantic_core==2.27.2
|
||||
pydotplus==2.0.2
|
||||
pydyf==0.11.0
|
||||
PyGetWindow==0.0.9
|
||||
Pygments==2.19.1
|
||||
PyJWT==2.10.1
|
||||
pylint==3.3.4
|
||||
PyMsgBox==1.0.9
|
||||
PyMySQL==1.1.1
|
||||
pyobjc-core==11.0
|
||||
pyobjc-framework-Cocoa==11.0
|
||||
pyobjc-framework-Quartz==11.0
|
||||
pyparsing==3.2.1
|
||||
pyperclip==1.9.0
|
||||
pyphen==0.17.2
|
||||
pypng==0.20220715.0
|
||||
PyRect==0.2.0
|
||||
PyScreeze==1.0.1
|
||||
pyserial==3.5
|
||||
PySocks==1.7.1
|
||||
python-bidi==0.6.3
|
||||
python-dateutil==2.9.0.post0
|
||||
python-docx==1.1.2
|
||||
python-openid==2.2.5
|
||||
python-stdnum==1.20
|
||||
python3-saml==1.16.0
|
||||
pytweening==1.2.0
|
||||
pytz==2024.2
|
||||
pyvin==0.0.2
|
||||
pywa==2.7.0
|
||||
pywhat==5.1.0
|
||||
pywhatkit==5.4
|
||||
PyYAML==6.0.2
|
||||
pyzbar==0.1.9
|
||||
qrcode==7.4.2
|
||||
RapidFuzz==3.11.0
|
||||
regex==2024.11.6
|
||||
reportlab==4.2.5
|
||||
requests==2.32.3
|
||||
requests-oauthlib==2.0.0
|
||||
rfc3986==2.0.0
|
||||
rich==10.16.2
|
||||
rubicon-objc==0.5.0
|
||||
sacremoses==0.1.1
|
||||
scikit-image==0.25.1
|
||||
scikit-learn==1.6.1
|
||||
scipy==1.15.1
|
||||
selenium==4.28.1
|
||||
sentencepiece==0.2.0
|
||||
shapely==2.0.6
|
||||
simsimd==6.2.1
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
snowballstemmer==2.2.0
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.6
|
||||
SQLAlchemy==2.0.37
|
||||
sqlparse==0.5.3
|
||||
stanza==1.10.1
|
||||
stringzilla==3.11.3
|
||||
suds==1.2.0
|
||||
swapper==1.3.0
|
||||
sympy==1.13.1
|
||||
tablib==3.8.0
|
||||
termcolor==2.5.0
|
||||
threadpoolctl==3.5.0
|
||||
tifffile==2025.1.10
|
||||
tinycss2==1.4.0
|
||||
tinyhtml5==2.0.0
|
||||
tomli==2.2.1
|
||||
tomlkit==0.13.2
|
||||
torch==2.5.1
|
||||
tqdm==4.67.1
|
||||
trio==0.28.0
|
||||
trio-websocket==0.11.1
|
||||
twilio==9.4.4
|
||||
typing-inspect==0.9.0
|
||||
typing_extensions==4.12.2
|
||||
tzdata==2025.1
|
||||
Unidecode==1.3.8
|
||||
upgrade-requirements==1.7.0
|
||||
urllib3==2.3.0
|
||||
vin==0.6.2
|
||||
vininfo==1.8.0
|
||||
vishap==0.1.5
|
||||
vpic-api==0.7.4
|
||||
weasyprint==63.1
|
||||
webencodings==0.5.1
|
||||
websocket-client==1.8.0
|
||||
Werkzeug==3.1.3
|
||||
wikipedia==1.4.0
|
||||
wsproto==1.2.0
|
||||
xmlsec==1.3.14
|
||||
yarl==1.18.3
|
||||
zopfli==0.2.3.post1
|
||||
|
||||
BIN
static/.DS_Store
vendored
BIN
static/images/.DS_Store
vendored
BIN
static/images/bg/.DS_Store
vendored
Normal file
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
BIN
static/images/bg/haikal illustration dark-01.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
static/images/bg/haikal illustration dark-02.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
static/images/bg/haikal illustration dark-03.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
static/images/bg/haikal illustration dark-04.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
static/images/bg/haikal illustration dark-05.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
static/images/bg/haikal illustration dark-06.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
static/images/bg/haikal illustration dark-07.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
static/images/bg/haikal illustration dark-08.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
static/images/bg/haikal illustration dark-09.png
Normal file
|
After Width: | Height: | Size: 758 KiB |
BIN
static/images/bg/haikal illustration dark-10.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
static/images/bg/haikal illustration dark-11.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
static/images/bg/haikal illustration dark-12.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
static/images/logos/users/Icon_Black4x_LyRIMep.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/images/logos/users/Icon_Black4x_l7kxpIN_9tX4c3h.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/images/logos/users/appicon_RYe0YY6.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
static/images/logos/vendors/Alamjdouie-Hyundai-logo_I8WTQve_NvbZyE9_Bof5bry_lAvSIm4.png
vendored
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
static/images/logos/vendors/Aljumaih-Automotive-logo_8To29ER.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/logos/vendors/Aljumaih-Automotive-logo_8To29ER_6VADgHf.png
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/images/spot-illustrations/.DS_Store
vendored
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 127 KiB |
BIN
static/images/spot-illustrations/22_2999.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 99 KiB |
BIN
static/images/spot-illustrations/dark_22000.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 119 KiB |
BIN
templates/.DS_Store
vendored
@ -1,37 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="row flex-center min-vh-100 py-5">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xxl-4"><a class="d-flex flex-center text-decoration-none mb-4" href="../../../index.html">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block"><img src="../../../assets/img/icons/logo.png" alt="phoenix" width="58" />
|
||||
</div>
|
||||
</a>
|
||||
<div class="px-xxl-5">
|
||||
<div class="text-center mb-6">
|
||||
<h4 class="text-body-highlight">Enter the verification code</h4>
|
||||
<p class="text-body-tertiary mb-0">An email containing a 6-digit verification code has been sent to the email address - exa*********.com </p>
|
||||
<P class="fs-10 mb-5">Don’t have access? <a href="#!">Use another method</a></P>
|
||||
<form class="verification-form" data-2fa-form="data-2fa-form">
|
||||
<div class="d-flex align-items-center gap-2 mb-3">
|
||||
<input class="form-control px-2 text-center" type="number" />
|
||||
<input class="form-control px-2 text-center" type="number" />
|
||||
<input class="form-control px-2 text-center" type="number" /><span>-</span>
|
||||
<input class="form-control px-2 text-center" type="number" />
|
||||
<input class="form-control px-2 text-center" type="number" />
|
||||
<input class="form-control px-2 text-center" type="number" />
|
||||
</div>
|
||||
<div class="form-check text-start mb-4">
|
||||
<input class="form-check-input" id="2fa-checkbox" type="checkbox" />
|
||||
<label for="2fa-checkbox">Don’t ask again on this device</label>
|
||||
</div>
|
||||
<Button class="btn btn-primary w-100 mb-5" type="submit" disabled="disabled">Verify</Button><a class="fs-9" href="#!">Didn’t receive the code? </a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
14
templates/account/account_inactive.html
Normal file
@ -0,0 +1,14 @@
|
||||
{% extends "allauth/layouts/entrance.html" %}
|
||||
{% load i18n %}
|
||||
{% load allauth %}
|
||||
{% block head_title %}
|
||||
{% translate "Account Inactive" %}
|
||||
{% endblock head_title %}
|
||||
{% block content %}
|
||||
{% element h1 %}
|
||||
{% translate "Account Inactive" %}
|
||||
{% endelement %}
|
||||
{% element p %}
|
||||
{% translate "This account is inactive." %}
|
||||
{% endelement %}
|
||||
{% endblock content %}
|
||||
@ -1,18 +1,48 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Confirm Email Verification Code{% endblock %}
|
||||
|
||||
{% extends "account/base_entrance.html" %}
|
||||
{% load i18n %}
|
||||
{% load allauth account %}
|
||||
{% block head_title %}
|
||||
{% translate "Email Verification" %}
|
||||
{% endblock head_title %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<h2>Confirm Your Email</h2>
|
||||
<p>Please enter the verification code sent to your email.</p>
|
||||
<form method="post" action="{% url 'account_confirm_email' %}">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label for="id_code" class="form-label">Verification Code</label>
|
||||
<input type="text" id="id_code" name="code" class="form-control">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Verify</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% element h1 %}
|
||||
{% translate "Enter Email Verification Code" %}
|
||||
{% endelement %}
|
||||
{% setvar email_link %}
|
||||
<a href="mailto:{{ email }}">{{ email }}</a>
|
||||
{% endsetvar %}
|
||||
{% element p %}
|
||||
{% blocktranslate %}We’ve sent a code to {{ email_link }}. The code expires shortly, so please enter it soon.{% endblocktranslate %}
|
||||
{% endelement %}
|
||||
{% url 'account_email_verification_sent' as action_url %}
|
||||
{% element form form=form method="post" action=action_url tags="entrance,email,verification" %}
|
||||
{% slot body %}
|
||||
{% csrf_token %}
|
||||
{% element fields form=form unlabeled=True %}
|
||||
{% endelement %}
|
||||
{{ redirect_field }}
|
||||
{% endslot %}
|
||||
{% slot actions %}
|
||||
{% element button type="submit" tags="prominent,confirm" %}
|
||||
{% translate "Confirm" %}
|
||||
{% endelement %}
|
||||
{% if cancel_url %}
|
||||
{% element button href=cancel_url tags="link,cancel" %}
|
||||
{% translate "Cancel" %}
|
||||
{% endelement %}
|
||||
{% else %}
|
||||
{% element button type="submit" form="logout-from-stage" tags="link,cancel" %}
|
||||
{% translate "Cancel" %}
|
||||
{% endelement %}
|
||||
{% endif %}
|
||||
{% endslot %}
|
||||
{% endelement %}
|
||||
{% if not cancel_url %}
|
||||
<form id="logout-from-stage"
|
||||
method="post"
|
||||
action="{% url 'account_logout' %}">
|
||||
<input type="hidden" name="next" value="{% url 'account_login' %}">
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
|
||||
@ -1,19 +1,49 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
|
||||
{% block title %}Confirm Login Code{% endblock %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load allauth account %}
|
||||
{% block head_title %}
|
||||
{% translate "Sign In" %}
|
||||
{% endblock head_title %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<h2>Confirm Login Code</h2>
|
||||
<p>Please enter the login code sent to your email or phone.</p>
|
||||
<form method="post" action="{% url 'account_confirm_login_code' %}">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label for="id_code" class="form-label">Login Code</label>
|
||||
<input type="text" id="id_code" name="code" class="form-control" required>
|
||||
<div class="row ">
|
||||
<div class="row flex-center min-vh-50">
|
||||
<div class="col-sm-10 col-md-8 col-lg-5 col-xl-5 col-xxl-3">
|
||||
<a class="d-flex flex-center text-decoration-none mb-4" href="{% url 'home' %}">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<div class="d-flex align-items-center fw-bolder fs-3 d-inline-block">
|
||||
<img class="d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
<img class="d-light-none" src="{% static 'images/logos/logo.png' %}" alt="{% trans 'home' %}" width="58" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Verify</button>
|
||||
</a>
|
||||
<div class="text-center">
|
||||
<h3 class="mb-4">{% translate "Enter Sign-In Code" %}</h3>
|
||||
</div>
|
||||
|
||||
{% setvar email_link %}
|
||||
<a href="mailto:{{ email }}">{{ email }}</a>
|
||||
{% endsetvar %}
|
||||
<p>
|
||||
{% blocktranslate %}We’ve sent a code to {{ email_link }}. The code expires shortly, so please enter it soon.{% endblocktranslate %}
|
||||
</p>
|
||||
<form method="post" action="{% url 'account_confirm_login_code' %}" class="form needs-validation" novalidate>
|
||||
{% csrf_token %}
|
||||
{{ redirect_field }}
|
||||
{{ form|crispy }}
|
||||
<button type="submit" class="btn btn-primary btn-sm w-100">{% trans "Sign In" %}</button>
|
||||
</form>
|
||||
<p>If you didn’t receive a code, <a href="{% url 'account_resend_login_code' %}">click here</a> to resend it.</p>
|
||||
{% element button type="submit" form="logout-from-stage" tags="link" %}
|
||||
{% translate "Cancel" %}
|
||||
{% endelement %}
|
||||
<form id="logout-from-stage"
|
||||
method="post"
|
||||
action="{% url 'account_logout' %}">
|
||||
<input type="hidden" name="next" value="{% url 'account_login' %}">
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
90
templates/account/email.html
Normal file
@ -0,0 +1,90 @@
|
||||
{% extends "account/base_manage_email.html" %}
|
||||
{% load allauth i18n %}
|
||||
{% block head_title %}
|
||||
{% trans "Email Addresses" %}
|
||||
{% endblock head_title %}
|
||||
{% block content %}
|
||||
{% element h1 %}
|
||||
{% trans "Email Addresses" %}
|
||||
{% endelement %}
|
||||
{% if emailaddresses %}
|
||||
{% element p %}
|
||||
{% trans 'The following email addresses are associated with your account:' %}
|
||||
{% endelement %}
|
||||
{% url 'account_email' as email_url %}
|
||||
{% element form form=form action=email_url method="post" tags="email,list" %}
|
||||
{% slot body %}
|
||||
{% csrf_token %}
|
||||
{% for radio in emailaddress_radios %}
|
||||
{% with emailaddress=radio.emailaddress %}
|
||||
{% element field type="radio" checked=radio.checked name="email" value=emailaddress.email id=radio.id %}
|
||||
{% slot label %}
|
||||
{{ emailaddress.email }}
|
||||
{% if emailaddress.verified %}
|
||||
{% element badge tags="success,email,verified" %}
|
||||
{% translate "Verified" %}
|
||||
{% endelement %}
|
||||
{% else %}
|
||||
{% element badge tags="warning,email,unverified" %}
|
||||
{% translate "Unverified" %}
|
||||
{% endelement %}
|
||||
{% endif %}
|
||||
{% if emailaddress.primary %}
|
||||
{% element badge tags="email,primary" %}
|
||||
{% translate "Primary" %}
|
||||
{% endelement %}
|
||||
{% endif %}
|
||||
{% endslot %}
|
||||
{% endelement %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% endslot %}
|
||||
{% slot actions %}
|
||||
{% element button type="submit" name="action_primary" %}
|
||||
{% trans 'Make Primary' %}
|
||||
{% endelement %}
|
||||
{% element button tags="secondary" type="submit" name="action_send" %}
|
||||
{% trans 'Re-send Verification' %}
|
||||
{% endelement %}
|
||||
{% element button tags="danger,delete" type="submit" name="action_remove" %}
|
||||
{% trans 'Remove' %}
|
||||
{% endelement %}
|
||||
{% endslot %}
|
||||
{% endelement %}
|
||||
{% else %}
|
||||
{% include "account/snippets/warn_no_email.html" %}
|
||||
{% endif %}
|
||||
{% if can_add_email %}
|
||||
{% element h2 %}
|
||||
{% trans "Add Email Address" %}
|
||||
{% endelement %}
|
||||
{% url 'account_email' as action_url %}
|
||||
{% element form form=form method="post" action=action_url tags="email,add" %}
|
||||
{% slot body %}
|
||||
{% csrf_token %}
|
||||
{% element fields form=form %}
|
||||
{% endelement %}
|
||||
{% endslot %}
|
||||
{% slot actions %}
|
||||
{% element button name="action_add" type="submit" %}
|
||||
{% trans "Add Email" %}
|
||||
{% endelement %}
|
||||
{% endslot %}
|
||||
{% endelement %}
|
||||
{% endif %}
|
||||
{% endblock content %}
|
||||
{% block extra_body %}
|
||||
<script>
|
||||
(function() {
|
||||
var message = "{% trans 'Do you really want to remove the selected email address?' %}";
|
||||
var actions = document.getElementsByName('action_remove');
|
||||
if (actions.length) {
|
||||
actions[0].addEventListener("click", function(e) {
|
||||
if (! confirm(message)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{% endblock extra_body %}
|
||||
13
templates/account/email/account_already_exists_message.txt
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "account/email/base_message.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}{% autoescape off %}{% blocktrans %}You are receiving this email because you or someone else tried to signup for an
|
||||
account using email address:
|
||||
|
||||
{{ email }}
|
||||
|
||||
However, an account using that email address already exists. In case you have
|
||||
forgotten about this, please use the password forgotten procedure to recover
|
||||
your account:
|
||||
|
||||
{{ password_reset_url }}{% endblocktrans %}{% endautoescape %}{% endblock content %}
|
||||
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Account Already Exists{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
7
templates/account/email/base_message.txt
Normal file
@ -0,0 +1,7 @@
|
||||
{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name %}Hello from {{ site_name }}!{% endblocktrans %}
|
||||
|
||||
{% block content %}{% endblock content %}
|
||||
|
||||
{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you for using {{ site_name }}!
|
||||
{{ site_domain }}{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
14
templates/account/email/base_notification.txt
Normal file
@ -0,0 +1,14 @@
|
||||
{% extends "account/email/base_message.txt" %}
|
||||
{% load account %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}{% autoescape off %}{% blocktrans %}You are receiving this mail because the following change was made to your account:{% endblocktrans %}
|
||||
|
||||
{% block notification_message %}
|
||||
{% endblock notification_message%}
|
||||
|
||||
{% blocktrans %}If you do not recognize this change then please take proper security precautions immediately. The change to your account originates from:
|
||||
|
||||
- IP address: {{ip}}
|
||||
- Browser: {{user_agent}}
|
||||
- Date: {{timestamp}}{% endblocktrans %}{% endautoescape %}{% endblock %}
|
||||
4
templates/account/email/email_changed_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Your email has been changed from {{ from_email }} to {{ to_email }}.{% endblocktrans %}{% endblock notification_message %}
|
||||
4
templates/account/email/email_changed_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Email Changed{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
4
templates/account/email/email_confirm_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Your email has been confirmed.{% endblocktrans %}{% endblock notification_message %}
|
||||
4
templates/account/email/email_confirm_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Email Confirmation{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
9
templates/account/email/email_confirmation_message.txt
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "account/email/base_message.txt" %}
|
||||
{% load account %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}{% autoescape off %}{% user_display user as user_display %}{% blocktranslate with site_name=current_site.name site_domain=current_site.domain %}You're receiving this email because user {{ user_display }} has given your email address to register an account on {{ site_domain }}.{% endblocktranslate %}
|
||||
|
||||
{% if code %}{% blocktranslate %}Your email verification code is listed below. Please enter it in your open browser window.{% endblocktranslate %}
|
||||
|
||||
{{ code }}{% else %}{% blocktranslate %}To confirm this is correct, go to {{ activate_url }}{% endblocktranslate %}{% endif %}{% endautoescape %}{% endblock content %}
|
||||
@ -0,0 +1 @@
|
||||
{% include "account/email/email_confirmation_message.txt" %}
|
||||
@ -0,0 +1 @@
|
||||
{% include "account/email/email_confirmation_subject.txt" %}
|
||||
4
templates/account/email/email_confirmation_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Please Confirm Your Email Address{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
4
templates/account/email/email_deleted_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Email address {{ deleted_email }} has been removed from your account.{% endblocktrans %}{% endblock notification_message %}
|
||||
4
templates/account/email/email_deleted_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Email Removed{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
9
templates/account/email/login_code_message.txt
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "account/email/base_message.txt" %}
|
||||
{% load account %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}{% autoescape off %}{% blocktranslate %}Your sign-in code is listed below. Please enter it in your open browser window.{% endblocktranslate %}{% endautoescape %}
|
||||
|
||||
{{ code }}
|
||||
|
||||
{% blocktranslate %}This mail can be safely ignored if you did not initiate this action.{% endblocktranslate %}{% endblock content %}
|
||||
4
templates/account/email/login_code_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Sign-In Code{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
4
templates/account/email/password_changed_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Your password has been changed.{% endblocktrans %}{% endblock notification_message %}
|
||||
4
templates/account/email/password_changed_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Password Changed{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
9
templates/account/email/password_reset_key_message.txt
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "account/email/base_message.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}{% autoescape off %}{% blocktrans %}You're receiving this email because you or someone else has requested a password reset for your user account.
|
||||
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %}
|
||||
|
||||
{{ password_reset_url }}{% if username %}
|
||||
|
||||
{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %}{% endif %}{% endautoescape %}{% endblock content %}
|
||||
4
templates/account/email/password_reset_key_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Password Reset Email{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
4
templates/account/email/password_reset_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Your password has been reset.{% endblocktrans %}{% endblock notification_message %}
|
||||
4
templates/account/email/password_reset_subject.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Password Reset{% endblocktrans %}
|
||||
{% endautoescape %}
|
||||
4
templates/account/email/password_set_message.txt
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "account/email/base_notification.txt" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block notification_message %}{% blocktrans %}Your password has been set.{% endblocktrans %}{% endblock notification_message %}
|
||||