fix error in gitignore

This commit is contained in:
2026-09-24 12:32:59 +03:30
commit 86c117ee2a
165 changed files with 5963 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
# core management commands
@@ -0,0 +1 @@
# commands
+176
View File
@@ -0,0 +1,176 @@
"""Seed demo data: roles, users, facilities/schedules/slots, a complete default
workflow (with approval + payment + invoice + Odoo-sync steps), pricing rules,
notification templates and a report definition.
The workflow seeded here is demo DATA ONLY — the engine itself remains fully
dynamic and knows nothing about pistachio processing.
"""
from decimal import Decimal
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.db import transaction
from django.utils import timezone
from apps.accounts.models import Customer
from apps.notifications.models import NotificationTemplate
from apps.pricing.models import PricingRule
from apps.rbac.models import Permission, Role
from apps.reports.models import ReportDefinition, ReportField
from apps.reservations.models import Facility, FacilitySchedule
from apps.reservations.slot_service import SlotService
from apps.workflows.engine import WorkflowEngine
from apps.workflows.models import Workflow, WorkflowStep, WorkflowTransition, WorkflowVersion
User = get_user_model()
PERMISSIONS = [
"reservation.view", "reservation.create", "reservation.update", "reservation.cancel", "reservation.approve",
"slot.manage",
"weighing.view", "weighing.create", "weighing.update",
"workflow.view", "workflow.create", "workflow.update", "workflow.publish",
"processing.view", "processing.start", "processing.pause", "processing.complete",
"invoice.view", "invoice.create", "invoice.cancel",
"report.view", "report.create",
"user.view", "user.manage", "role.view", "role.manage",
"settings.manage",
]
ROLE_SPECS = {
"administrator": ("Administrator", PERMISSIONS),
"facility_manager": ("Facility Manager", [
"reservation.view", "reservation.update", "reservation.cancel", "reservation.approve", "slot.manage",
"weighing.view", "weighing.create", "weighing.update",
"processing.view", "processing.start", "processing.complete",
"invoice.view", "report.view", "report.create", "user.view",
]),
"operator": ("Operator", [
"reservation.view", "weighing.view", "weighing.create",
"processing.view", "processing.start", "processing.pause", "processing.complete",
]),
"customer": ("Customer", ["reservation.view", "reservation.create", "processing.view", "report.view"]),
"accountant": ("Accountant", ["invoice.view", "invoice.create", "invoice.cancel", "report.view"]),
"quality_controller": ("Quality Controller", ["processing.view", "processing.complete", "report.create"]),
}
# (key, name, flags)
STEP_DEFS = [
("reservation", "Reservation", {"is_start": True}),
("approval", "Approval", {}),
("weighing", "Weighing", {"required": True}),
("processing_selection", "Processing Selection", {"required": True}),
("customer_confirmation", "Customer Confirmation", {"requires_customer_confirmation": True}),
("payment", "Payment", {"requires_payment": True}),
("sorting", "Sorting", {}),
("washing", "Washing", {}),
("drying", "Drying", {}),
("quality_control", "Quality Control", {}),
("packaging", "Packaging", {}),
("final_weighing", "Final Weighing", {}),
("final_report", "Final Report", {}),
("invoice", "Invoice", {"triggers_invoice": True, "triggers_odoo_sync": True}),
("completed", "Completed", {"is_terminal": True}),
]
REPORT_FIELDS = [
("final_moisture", "Final Moisture", "decimal"),
("quality_grade", "Quality Grade", "choice"),
("broken_percentage", "Broken Percentage", "percentage"),
("category_a_weight", "Category A Weight", "weight"),
("category_b_weight", "Category B Weight", "weight"),
("category_c_weight", "Category C Weight", "weight"),
]
class Command(BaseCommand):
help = "Seed demo roles, users, facilities, a default workflow, pricing, templates and reports."
@transaction.atomic
def handle(self, *args, **options):
perms = {}
for code in PERMISSIONS:
perms[code], _ = Permission.objects.get_or_create(code=code, defaults={"description": code})
roles = {}
for slug, (name, codes) in ROLE_SPECS.items():
role, _ = Role.objects.get_or_create(slug=slug, defaults={"name": name})
role.permissions.set([perms[c] for c in codes])
roles[slug] = role
def make_user(username, role_slug, **kw):
user, _ = User.objects.get_or_create(username=username, defaults=kw)
user.set_password("demo1234")
user.save()
if not user.user_roles.filter(role=roles[role_slug]).exists():
user.user_roles.create(role=roles[role_slug])
return user
make_user("admin", "administrator", is_staff=True, is_superuser=True, email="admin@example.com")
make_user("manager", "facility_manager")
make_user("operator", "operator")
make_user("accountant", "accountant")
make_user("qc", "quality_controller")
cust_user = make_user("customer", "customer", email="customer@example.com", phone="09120000000")
Customer.objects.get_or_create(user=cust_user, defaults={"company_name": "Demo Pistachio Co."})
# Facility + schedule + slots
facility, _ = Facility.objects.get_or_create(name="Main Facility")
tomorrow = timezone.localdate() + timezone.timedelta(days=1)
FacilitySchedule.objects.update_or_create(
facility=facility, date=tomorrow, defaults={"is_open": True, "capacity": 3}
)
SlotService().generate_slots(facility, tomorrow)
# Default workflow
workflow, _ = Workflow.objects.get_or_create(
slug="pistachio-processing",
defaults={"name": "Pistachio Processing", "description": "Default configurable workflow"},
)
version = WorkflowVersion.objects.create(workflow=workflow, version=workflow.versions.count() + 1)
steps = {}
for order, (key, name, flags) in enumerate(STEP_DEFS):
steps[key] = WorkflowStep.objects.create(
version=version, key=key, name=name, order=order,
position_x=80 + (order % 5) * 200, position_y=40 + (order // 5) * 160,
**flags,
)
chain = [d[0] for d in STEP_DEFS]
for a, b in zip(chain, chain[1:]):
WorkflowTransition.objects.create(version=version, from_step=steps[a], to_step=steps[b])
# Pricing
PricingRule.objects.get_or_create(step=steps["washing"], name="Washing per kg", rule_type="per_kg", amount=Decimal("5000"))
PricingRule.objects.get_or_create(step=steps["drying"], name="Drying per kg", rule_type="per_kg", amount=Decimal("8000"))
PricingRule.objects.get_or_create(step=steps["sorting"], name="Sorting per kg", rule_type="per_kg", amount=Decimal("12000"))
# Report definition
definition, _ = ReportDefinition.objects.get_or_create(
workflow=workflow, name="Default Processing Report", defaults={"active": True}
)
for order, (key, label, field_type) in enumerate(REPORT_FIELDS):
ReportField.objects.get_or_create(
definition=definition, key=key,
defaults={"label": label, "field_type": field_type, "order": order},
)
# Notification templates
NotificationTemplate.objects.get_or_create(
event="reservation.approved", channel="sms",
defaults={"body": "Cetana: reservation {{reservation_title}} on {{slot_date}} at {{slot_time}} is confirmed."},
)
NotificationTemplate.objects.get_or_create(
event="order.completed", channel="sms",
defaults={"body": "Cetana: order {{order_number}} is complete. Final report is ready."},
)
try:
WorkflowEngine().publish(workflow, version)
except Exception as exc: # pragma: no cover
self.stdout.write(self.style.WARNING(f"Workflow publish skipped: {exc}"))
# Pre-fill the Odoo server URL (credentials are entered in Settings).
from apps.core.models import SystemSetting
SystemSetting.objects.get_or_create(key="odoo.url", defaults={"value": "https://rayayazd.ir"})
self.stdout.write(self.style.SUCCESS("Seed data created. Logins use password 'demo1234'."))