Complete Accounting sidebar modules with ops CRUD, BFF proxy, and treasury APIs.
Wire nested nav pages for phases 5.1-5.11 to real list/create endpoints, fix COA import connectivity via same-origin proxy, and add operational migration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
12c8615615
commit
7d66932da8
@ -0,0 +1,73 @@
|
|||||||
|
"""Alembic: operational docs, inventory items, warehouses."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
from app.models.types import GUID
|
||||||
|
|
||||||
|
revision = "0003_operational"
|
||||||
|
down_revision = "0002_phases_57_511"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.create_table(
|
||||||
|
"business_documents",
|
||||||
|
sa.Column("id", GUID(), primary_key=True),
|
||||||
|
sa.Column("tenant_id", GUID(), nullable=False),
|
||||||
|
sa.Column("module", sa.String(40), nullable=False),
|
||||||
|
sa.Column("doc_type", sa.String(50), nullable=False),
|
||||||
|
sa.Column("number", sa.String(50), nullable=False),
|
||||||
|
sa.Column("doc_date", sa.Date(), nullable=False),
|
||||||
|
sa.Column("party_name", sa.String(255), nullable=True),
|
||||||
|
sa.Column("party_id", GUID(), nullable=True),
|
||||||
|
sa.Column("amount", sa.Numeric(18, 4), nullable=False, server_default="0"),
|
||||||
|
sa.Column("status", sa.String(30), nullable=False, server_default="draft"),
|
||||||
|
sa.Column("description", sa.Text(), nullable=True),
|
||||||
|
sa.Column("meta_json", sa.Text(), nullable=True),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.UniqueConstraint("tenant_id", "module", "number", name="uq_biz_doc_tenant_module_number"),
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
"ix_biz_doc_tenant_module_type",
|
||||||
|
"business_documents",
|
||||||
|
["tenant_id", "module", "doc_type"],
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"inventory_items",
|
||||||
|
sa.Column("id", GUID(), primary_key=True),
|
||||||
|
sa.Column("tenant_id", GUID(), nullable=False),
|
||||||
|
sa.Column("code", sa.String(50), nullable=False),
|
||||||
|
sa.Column("name", sa.String(255), nullable=False),
|
||||||
|
sa.Column("item_type", sa.String(30), nullable=False, server_default="goods"),
|
||||||
|
sa.Column("unit", sa.String(30), nullable=False, server_default="عدد"),
|
||||||
|
sa.Column("quantity_on_hand", sa.Numeric(18, 4), nullable=False, server_default="0"),
|
||||||
|
sa.Column("unit_cost", sa.Numeric(18, 4), nullable=False, server_default="0"),
|
||||||
|
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.UniqueConstraint("tenant_id", "code", name="uq_inventory_item_tenant_code"),
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"warehouses",
|
||||||
|
sa.Column("id", GUID(), primary_key=True),
|
||||||
|
sa.Column("tenant_id", GUID(), nullable=False),
|
||||||
|
sa.Column("code", sa.String(50), nullable=False),
|
||||||
|
sa.Column("name", sa.String(255), nullable=False),
|
||||||
|
sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.true()),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||||
|
sa.UniqueConstraint("tenant_id", "code", name="uq_warehouse_tenant_code"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_table("warehouses")
|
||||||
|
op.drop_table("inventory_items")
|
||||||
|
op.drop_index("ix_biz_doc_tenant_module_type", table_name="business_documents")
|
||||||
|
op.drop_table("business_documents")
|
||||||
@ -23,7 +23,7 @@ __all__ = [
|
|||||||
|
|
||||||
def get_pagination(
|
def get_pagination(
|
||||||
page: int = Query(default=1, ge=1),
|
page: int = Query(default=1, ge=1),
|
||||||
page_size: int = Query(default=20, ge=1, le=100),
|
page_size: int = Query(default=20, ge=1, le=500),
|
||||||
) -> PaginationParams:
|
) -> PaginationParams:
|
||||||
return PaginationParams(page=page, page_size=page_size)
|
return PaginationParams(page=page, page_size=page_size)
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from app.api.v1 import (
|
|||||||
fixed_assets,
|
fixed_assets,
|
||||||
health,
|
health,
|
||||||
ledger,
|
ledger,
|
||||||
|
operational,
|
||||||
payroll,
|
payroll,
|
||||||
posting,
|
posting,
|
||||||
purchase_inventory,
|
purchase_inventory,
|
||||||
@ -31,3 +32,4 @@ api_router.include_router(payroll.router, prefix="/payroll", tags=["payroll"])
|
|||||||
api_router.include_router(reporting.router, prefix="/reporting", tags=["reporting"])
|
api_router.include_router(reporting.router, prefix="/reporting", tags=["reporting"])
|
||||||
api_router.include_router(compliance.router, prefix="/compliance", tags=["compliance"])
|
api_router.include_router(compliance.router, prefix="/compliance", tags=["compliance"])
|
||||||
api_router.include_router(setup.router, prefix="/setup", tags=["setup"])
|
api_router.include_router(setup.router, prefix="/setup", tags=["setup"])
|
||||||
|
api_router.include_router(operational.router, prefix="/ops", tags=["ops"])
|
||||||
|
|||||||
@ -105,6 +105,25 @@ async def create_audit_record(
|
|||||||
return {"id": str(record.id)}
|
return {"id": str(record.id)}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/policies")
|
||||||
|
async def list_compliance_policies(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await CompliancePolicyRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(p.id),
|
||||||
|
"code": p.code,
|
||||||
|
"name": p.name,
|
||||||
|
"policy_type": p.policy_type,
|
||||||
|
"is_active": getattr(p, "is_active", True),
|
||||||
|
}
|
||||||
|
for p in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@router.post("/policies", status_code=status.HTTP_201_CREATED)
|
@router.post("/policies", status_code=status.HTTP_201_CREATED)
|
||||||
async def create_compliance_policy(
|
async def create_compliance_policy(
|
||||||
body: CompliancePolicyCreate,
|
body: CompliancePolicyCreate,
|
||||||
|
|||||||
218
backend/services/accounting/app/api/v1/operational.py
Normal file
218
backend/services/accounting/app/api/v1/operational.py
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
"""Operational documents + inventory masters API."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
from decimal import Decimal
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Query, status
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.api.deps import get_db, require_tenant
|
||||||
|
from app.core.security import get_current_user
|
||||||
|
from app.models.operational import BusinessDocument, InventoryItem, Warehouse
|
||||||
|
from app.repositories.base import TenantBaseRepository
|
||||||
|
from shared.exceptions import NotFoundError
|
||||||
|
from shared.security import CurrentUser
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
class BizDocCreate(BaseModel):
|
||||||
|
module: str = Field(max_length=40)
|
||||||
|
doc_type: str = Field(max_length=50)
|
||||||
|
number: str = Field(max_length=50)
|
||||||
|
doc_date: date
|
||||||
|
party_name: str | None = None
|
||||||
|
party_id: UUID | None = None
|
||||||
|
amount: Decimal = Decimal("0")
|
||||||
|
status: str = "draft"
|
||||||
|
description: str | None = None
|
||||||
|
meta_json: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class BizDocUpdate(BaseModel):
|
||||||
|
party_name: str | None = None
|
||||||
|
amount: Decimal | None = None
|
||||||
|
status: str | None = None
|
||||||
|
description: str | None = None
|
||||||
|
doc_date: date | None = None
|
||||||
|
meta_json: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class BizDocRead(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
tenant_id: UUID
|
||||||
|
module: str
|
||||||
|
doc_type: str
|
||||||
|
number: str
|
||||||
|
doc_date: date
|
||||||
|
party_name: str | None
|
||||||
|
amount: Decimal
|
||||||
|
status: str
|
||||||
|
description: str | None
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class ItemCreate(BaseModel):
|
||||||
|
code: str
|
||||||
|
name: str
|
||||||
|
item_type: str = "goods"
|
||||||
|
unit: str = "عدد"
|
||||||
|
quantity_on_hand: Decimal = Decimal("0")
|
||||||
|
unit_cost: Decimal = Decimal("0")
|
||||||
|
|
||||||
|
|
||||||
|
class ItemRead(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
code: str
|
||||||
|
name: str
|
||||||
|
item_type: str
|
||||||
|
unit: str
|
||||||
|
quantity_on_hand: Decimal
|
||||||
|
unit_cost: Decimal
|
||||||
|
is_active: bool
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class WarehouseCreate(BaseModel):
|
||||||
|
code: str
|
||||||
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
class WarehouseRead(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
code: str
|
||||||
|
name: str
|
||||||
|
is_active: bool
|
||||||
|
|
||||||
|
model_config = {"from_attributes": True}
|
||||||
|
|
||||||
|
|
||||||
|
class BizDocRepo(TenantBaseRepository[BusinessDocument]):
|
||||||
|
model = BusinessDocument
|
||||||
|
|
||||||
|
|
||||||
|
class ItemRepo(TenantBaseRepository[InventoryItem]):
|
||||||
|
model = InventoryItem
|
||||||
|
|
||||||
|
|
||||||
|
class WarehouseRepo(TenantBaseRepository[Warehouse]):
|
||||||
|
model = Warehouse
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/documents", response_model=list[BizDocRead])
|
||||||
|
async def list_documents(
|
||||||
|
module: str | None = Query(default=None),
|
||||||
|
doc_type: str | None = Query(default=None),
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
stmt = select(BusinessDocument).where(BusinessDocument.tenant_id == tenant_id)
|
||||||
|
if module:
|
||||||
|
stmt = stmt.where(BusinessDocument.module == module)
|
||||||
|
if doc_type:
|
||||||
|
stmt = stmt.where(BusinessDocument.doc_type == doc_type)
|
||||||
|
stmt = stmt.order_by(BusinessDocument.doc_date.desc()).limit(200)
|
||||||
|
result = await db.execute(stmt)
|
||||||
|
return list(result.scalars().all())
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/documents", response_model=BizDocRead, status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_document(
|
||||||
|
body: BizDocCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = BusinessDocument(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await BizDocRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(entity)
|
||||||
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
@router.patch("/documents/{doc_id}", response_model=BizDocRead)
|
||||||
|
async def update_document(
|
||||||
|
doc_id: UUID,
|
||||||
|
body: BizDocUpdate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
repo = BizDocRepo(db)
|
||||||
|
entity = await repo.get(tenant_id, doc_id)
|
||||||
|
if entity is None:
|
||||||
|
raise NotFoundError("سند یافت نشد", error_code="document_not_found")
|
||||||
|
for k, v in body.model_dump(exclude_unset=True).items():
|
||||||
|
setattr(entity, k, v)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(entity)
|
||||||
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/documents/{doc_id}/confirm", response_model=BizDocRead)
|
||||||
|
async def confirm_document(
|
||||||
|
doc_id: UUID,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = await BizDocRepo(db).get(tenant_id, doc_id)
|
||||||
|
if entity is None:
|
||||||
|
raise NotFoundError("سند یافت نشد", error_code="document_not_found")
|
||||||
|
entity.status = "confirmed"
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(entity)
|
||||||
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/items", response_model=list[ItemRead])
|
||||||
|
async def list_items(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
return await ItemRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/items", response_model=ItemRead, status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_item(
|
||||||
|
body: ItemCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = InventoryItem(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await ItemRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(entity)
|
||||||
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/warehouses", response_model=list[WarehouseRead])
|
||||||
|
async def list_warehouses(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
return await WarehouseRepo(db).list_by_tenant(tenant_id, limit=100)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/warehouses", response_model=WarehouseRead, status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_warehouse(
|
||||||
|
body: WarehouseCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = Warehouse(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await WarehouseRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(entity)
|
||||||
|
return entity
|
||||||
@ -204,3 +204,256 @@ async def update_cash_box(
|
|||||||
await db.commit()
|
await db.commit()
|
||||||
await db.refresh(entity)
|
await db.refresh(entity)
|
||||||
return CashBoxRead.model_validate(entity)
|
return CashBoxRead.model_validate(entity)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Cheques / transfers / receipts / payments / reconciliation ───────────────
|
||||||
|
|
||||||
|
from app.models.treasury import Cheque, PaymentVoucher, ReceiptVoucher, Reconciliation, Transfer
|
||||||
|
from app.models.types import ChequeStatus, ReconciliationStatus
|
||||||
|
|
||||||
|
|
||||||
|
class ChequeRepo(TenantBaseRepository[Cheque]):
|
||||||
|
model = Cheque
|
||||||
|
|
||||||
|
|
||||||
|
class TransferRepo(TenantBaseRepository[Transfer]):
|
||||||
|
model = Transfer
|
||||||
|
|
||||||
|
|
||||||
|
class ReceiptRepo(TenantBaseRepository[ReceiptVoucher]):
|
||||||
|
model = ReceiptVoucher
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentRepo(TenantBaseRepository[PaymentVoucher]):
|
||||||
|
model = PaymentVoucher
|
||||||
|
|
||||||
|
|
||||||
|
class ReconciliationRepo(TenantBaseRepository[Reconciliation]):
|
||||||
|
model = Reconciliation
|
||||||
|
|
||||||
|
|
||||||
|
class ChequeCreate(BaseModel):
|
||||||
|
cheque_number: str
|
||||||
|
amount: Decimal
|
||||||
|
issue_date: date
|
||||||
|
due_date: date | None = None
|
||||||
|
is_incoming: bool = True
|
||||||
|
payee: str | None = None
|
||||||
|
bank_account_id: UUID | None = None
|
||||||
|
status: ChequeStatus = ChequeStatus.RECEIVED
|
||||||
|
|
||||||
|
|
||||||
|
class TransferCreate(BaseModel):
|
||||||
|
transfer_date: date
|
||||||
|
amount: Decimal
|
||||||
|
from_type: str
|
||||||
|
from_id: UUID
|
||||||
|
to_type: str
|
||||||
|
to_id: UUID
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ReceiptCreate(BaseModel):
|
||||||
|
receipt_number: str
|
||||||
|
receipt_date: date
|
||||||
|
amount: Decimal
|
||||||
|
payment_method: str = "cash"
|
||||||
|
cash_box_id: UUID | None = None
|
||||||
|
bank_account_id: UUID | None = None
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class PaymentCreate(BaseModel):
|
||||||
|
payment_number: str
|
||||||
|
payment_date: date
|
||||||
|
amount: Decimal
|
||||||
|
payment_method: str = "cash"
|
||||||
|
cash_box_id: UUID | None = None
|
||||||
|
bank_account_id: UUID | None = None
|
||||||
|
description: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ReconciliationCreate(BaseModel):
|
||||||
|
bank_account_id: UUID
|
||||||
|
statement_date: date
|
||||||
|
statement_balance: Decimal
|
||||||
|
book_balance: Decimal
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/cheques")
|
||||||
|
async def list_cheques(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await ChequeRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(c.id),
|
||||||
|
"cheque_number": c.cheque_number,
|
||||||
|
"amount": str(c.amount),
|
||||||
|
"issue_date": c.issue_date.isoformat(),
|
||||||
|
"due_date": c.due_date.isoformat() if c.due_date else None,
|
||||||
|
"status": c.status.value,
|
||||||
|
"is_incoming": c.is_incoming,
|
||||||
|
"payee": c.payee,
|
||||||
|
}
|
||||||
|
for c in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/cheques", status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_cheque(
|
||||||
|
body: ChequeCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = Cheque(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await ChequeRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
return {"id": str(entity.id), "cheque_number": entity.cheque_number}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/transfers")
|
||||||
|
async def list_transfers(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await TransferRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(t.id),
|
||||||
|
"transfer_date": t.transfer_date.isoformat(),
|
||||||
|
"amount": str(t.amount),
|
||||||
|
"from_type": t.from_type,
|
||||||
|
"from_id": str(t.from_id),
|
||||||
|
"to_type": t.to_type,
|
||||||
|
"to_id": str(t.to_id),
|
||||||
|
"description": t.description,
|
||||||
|
}
|
||||||
|
for t in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/transfers", status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_transfer(
|
||||||
|
body: TransferCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = Transfer(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await TransferRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
return {"id": str(entity.id)}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/receipts")
|
||||||
|
async def list_receipts(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await ReceiptRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(r.id),
|
||||||
|
"receipt_number": r.receipt_number,
|
||||||
|
"receipt_date": r.receipt_date.isoformat(),
|
||||||
|
"amount": str(r.amount),
|
||||||
|
"payment_method": r.payment_method,
|
||||||
|
"description": r.description,
|
||||||
|
}
|
||||||
|
for r in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/receipts", status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_receipt(
|
||||||
|
body: ReceiptCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = ReceiptVoucher(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await ReceiptRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
return {"id": str(entity.id)}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/payments")
|
||||||
|
async def list_payments(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await PaymentRepo(db).list_by_tenant(tenant_id, limit=200)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(p.id),
|
||||||
|
"payment_number": p.payment_number,
|
||||||
|
"payment_date": p.payment_date.isoformat(),
|
||||||
|
"amount": str(p.amount),
|
||||||
|
"payment_method": p.payment_method,
|
||||||
|
"description": p.description,
|
||||||
|
}
|
||||||
|
for p in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/payments", status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_payment(
|
||||||
|
body: PaymentCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
entity = PaymentVoucher(tenant_id=tenant_id, **body.model_dump())
|
||||||
|
await PaymentRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
return {"id": str(entity.id)}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/reconciliations")
|
||||||
|
async def list_reconciliations(
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
rows = await ReconciliationRepo(db).list_by_tenant(tenant_id, limit=100)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": str(r.id),
|
||||||
|
"bank_account_id": str(r.bank_account_id),
|
||||||
|
"statement_date": r.statement_date.isoformat(),
|
||||||
|
"statement_balance": str(r.statement_balance),
|
||||||
|
"book_balance": str(r.book_balance),
|
||||||
|
"difference": str(r.difference),
|
||||||
|
"status": r.status.value,
|
||||||
|
}
|
||||||
|
for r in rows
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/reconciliations", status_code=status.HTTP_201_CREATED)
|
||||||
|
async def create_reconciliation(
|
||||||
|
body: ReconciliationCreate,
|
||||||
|
tenant_id: UUID = Depends(require_tenant),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
_user: CurrentUser = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
diff = body.statement_balance - body.book_balance
|
||||||
|
entity = Reconciliation(
|
||||||
|
tenant_id=tenant_id,
|
||||||
|
bank_account_id=body.bank_account_id,
|
||||||
|
statement_date=body.statement_date,
|
||||||
|
statement_balance=body.statement_balance,
|
||||||
|
book_balance=body.book_balance,
|
||||||
|
difference=diff,
|
||||||
|
status=ReconciliationStatus.PENDING,
|
||||||
|
)
|
||||||
|
await ReconciliationRepo(db).add(entity)
|
||||||
|
await db.commit()
|
||||||
|
return {"id": str(entity.id), "difference": str(diff)}
|
||||||
|
|||||||
@ -140,3 +140,8 @@ from app.models.treasury import ( # noqa: F401
|
|||||||
Transfer,
|
Transfer,
|
||||||
TreasurySettings,
|
TreasurySettings,
|
||||||
)
|
)
|
||||||
|
from app.models.operational import ( # noqa: F401
|
||||||
|
BusinessDocument,
|
||||||
|
InventoryItem,
|
||||||
|
Warehouse,
|
||||||
|
)
|
||||||
|
|||||||
63
backend/services/accounting/app/models/operational.py
Normal file
63
backend/services/accounting/app/models/operational.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"""Phase ops — lightweight business documents for Sales/Purchase/Inventory UI."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
from datetime import date
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from sqlalchemy import Boolean, Date, Index, Numeric, String, Text, UniqueConstraint
|
||||||
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
|
from app.core.database import Base
|
||||||
|
from app.models.base import TenantMixin, TimestampMixin, UUIDPrimaryKeyMixin
|
||||||
|
from app.models.types import GUID
|
||||||
|
|
||||||
|
|
||||||
|
class BusinessDocument(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
|
||||||
|
"""Generic operational document used by Sales / Purchase / Inventory screens."""
|
||||||
|
|
||||||
|
__tablename__ = "business_documents"
|
||||||
|
|
||||||
|
module: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||||
|
doc_type: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
number: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
doc_date: Mapped[date] = mapped_column(Date, nullable=False)
|
||||||
|
party_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||||
|
party_id: Mapped[uuid.UUID | None] = mapped_column(GUID(), nullable=True)
|
||||||
|
amount: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
|
||||||
|
status: Mapped[str] = mapped_column(String(30), default="draft", nullable=False)
|
||||||
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
meta_json: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint("tenant_id", "module", "number", name="uq_biz_doc_tenant_module_number"),
|
||||||
|
Index("ix_biz_doc_tenant_module_type", "tenant_id", "module", "doc_type"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItem(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
|
||||||
|
__tablename__ = "inventory_items"
|
||||||
|
|
||||||
|
code: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
item_type: Mapped[str] = mapped_column(String(30), default="goods", nullable=False)
|
||||||
|
unit: Mapped[str] = mapped_column(String(30), default="عدد", nullable=False)
|
||||||
|
quantity_on_hand: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
|
||||||
|
unit_cost: Mapped[Decimal] = mapped_column(Numeric(18, 4), default=Decimal("0"), nullable=False)
|
||||||
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint("tenant_id", "code", name="uq_inventory_item_tenant_code"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Warehouse(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin):
|
||||||
|
__tablename__ = "warehouses"
|
||||||
|
|
||||||
|
code: Mapped[str] = mapped_column(String(50), nullable=False)
|
||||||
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||||
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint("tenant_id", "code", name="uq_warehouse_tenant_code"),
|
||||||
|
)
|
||||||
@ -283,6 +283,11 @@ async def import_coa_template(
|
|||||||
status_code=422,
|
status_code=422,
|
||||||
error_code="parent_missing",
|
error_code="parent_missing",
|
||||||
)
|
)
|
||||||
|
existing_acc = await account_repo.get_by_code(tenant_id, item.code)
|
||||||
|
if existing_acc is not None:
|
||||||
|
# Reuse existing account code so re-import / overlapping COA does not crash
|
||||||
|
code_to_id[item.code] = existing_acc.id
|
||||||
|
continue
|
||||||
acc = Account(
|
acc = Account(
|
||||||
tenant_id=tenant_id,
|
tenant_id=tenant_id,
|
||||||
chart_id=chart.id,
|
chart_id=chart.id,
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from pydantic import BaseModel, Field
|
|||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
DEFAULT_PAGE_SIZE = 20
|
DEFAULT_PAGE_SIZE = 20
|
||||||
MAX_PAGE_SIZE = 100
|
MAX_PAGE_SIZE = 500
|
||||||
|
|
||||||
|
|
||||||
class PaginationParams(BaseModel):
|
class PaginationParams(BaseModel):
|
||||||
|
|||||||
@ -189,6 +189,7 @@ services:
|
|||||||
NEXT_PUBLIC_KEYCLOAK_CLIENT_ID: ${NEXT_PUBLIC_KEYCLOAK_CLIENT_ID:-superapp-frontend}
|
NEXT_PUBLIC_KEYCLOAK_CLIENT_ID: ${NEXT_PUBLIC_KEYCLOAK_CLIENT_ID:-superapp-frontend}
|
||||||
NEXT_PUBLIC_PLATFORM_BASE_DOMAIN: ${NEXT_PUBLIC_PLATFORM_BASE_DOMAIN:-torbatyar.ir}
|
NEXT_PUBLIC_PLATFORM_BASE_DOMAIN: ${NEXT_PUBLIC_PLATFORM_BASE_DOMAIN:-torbatyar.ir}
|
||||||
NEXT_PUBLIC_ACCOUNTING_API_URL: ${NEXT_PUBLIC_ACCOUNTING_API_URL:-http://localhost:8002}
|
NEXT_PUBLIC_ACCOUNTING_API_URL: ${NEXT_PUBLIC_ACCOUNTING_API_URL:-http://localhost:8002}
|
||||||
|
ACCOUNTING_SERVICE_URL: ${ACCOUNTING_SERVICE_URL:-http://accounting-service:8002}
|
||||||
# polling برای hot-reload پایدار روی volume mount ویندوز
|
# polling برای hot-reload پایدار روی volume mount ویندوز
|
||||||
WATCHPACK_POLLING: "true"
|
WATCHPACK_POLLING: "true"
|
||||||
CHOKIDAR_USEPOLLING: "true"
|
CHOKIDAR_USEPOLLING: "true"
|
||||||
|
|||||||
7
frontend/app/accounting/ai/analytics/page.tsx
Normal file
7
frontend/app/accounting/ai/analytics/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="تحلیل هوشمند" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/anomalies/page.tsx
Normal file
7
frontend/app/accounting/ai/anomalies/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="کشف ناهنجاری" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/documents/page.tsx
Normal file
7
frontend/app/accounting/ai/documents/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="تحلیل اسناد" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/forecasts/page.tsx
Normal file
7
frontend/app/accounting/ai/forecasts/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="پیشبینیها" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/page.tsx
Normal file
7
frontend/app/accounting/ai/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="دستیار حسابداری" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/qa/page.tsx
Normal file
7
frontend/app/accounting/ai/qa/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="پرسش و پاسخ" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/recommendations/page.tsx
Normal file
7
frontend/app/accounting/ai/recommendations/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="پیشنهادهای هوشمند" />;
|
||||||
|
}
|
||||||
7
frontend/app/accounting/ai/reconciliation/page.tsx
Normal file
7
frontend/app/accounting/ai/reconciliation/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BlockedModulePage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <BlockedModulePage title="تطبیق هوشمند" />;
|
||||||
|
}
|
||||||
13
frontend/app/accounting/assets/accumulated/page.tsx
Normal file
13
frontend/app/accounting/assets/accumulated/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="استهلاک انباشته"
|
||||||
|
module="assets"
|
||||||
|
docType="accumulated"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
frontend/app/accounting/assets/dashboard/page.tsx
Normal file
5
frontend/app/accounting/assets/dashboard/page.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
redirect("/accounting/assets");
|
||||||
|
}
|
||||||
5
frontend/app/accounting/assets/depreciate/page.tsx
Normal file
5
frontend/app/accounting/assets/depreciate/page.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
redirect("/accounting/assets");
|
||||||
|
}
|
||||||
13
frontend/app/accounting/assets/dispose/page.tsx
Normal file
13
frontend/app/accounting/assets/dispose/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="معرفی و فروش دارایی"
|
||||||
|
module="assets"
|
||||||
|
docType="dispose"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/assets/schedule/page.tsx
Normal file
13
frontend/app/accounting/assets/schedule/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="برنامه استهلاک"
|
||||||
|
module="assets"
|
||||||
|
docType="schedule"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/assets/transfers/page.tsx
Normal file
13
frontend/app/accounting/assets/transfers/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="انتقال دارایی"
|
||||||
|
module="assets"
|
||||||
|
docType="transfer"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/assets/valuation/page.tsx
Normal file
13
frontend/app/accounting/assets/valuation/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="ارزشگذاری دارایی"
|
||||||
|
module="assets"
|
||||||
|
docType="valuation"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/control/page.tsx
Normal file
13
frontend/app/accounting/budget/control/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="کنترل بودجه"
|
||||||
|
module="budget"
|
||||||
|
docType="control"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/definitions/page.tsx
Normal file
13
frontend/app/accounting/budget/definitions/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تعریف بودجه"
|
||||||
|
module="budget"
|
||||||
|
docType="definition"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/forecast/page.tsx
Normal file
13
frontend/app/accounting/budget/forecast/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پیشبینی مالی"
|
||||||
|
module="budget"
|
||||||
|
docType="forecast"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/operational/page.tsx
Normal file
13
frontend/app/accounting/budget/operational/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="بودجهریزی عملیاتی"
|
||||||
|
module="budget"
|
||||||
|
docType="operational"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/performance/page.tsx
Normal file
13
frontend/app/accounting/budget/performance/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="مقایسه عملکرد"
|
||||||
|
module="budget"
|
||||||
|
docType="performance"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/reports/page.tsx
Normal file
13
frontend/app/accounting/budget/reports/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گزارش بودجه"
|
||||||
|
module="budget"
|
||||||
|
docType="report"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/scenarios/page.tsx
Normal file
13
frontend/app/accounting/budget/scenarios/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="سناریوهای مالی"
|
||||||
|
module="budget"
|
||||||
|
docType="scenario"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/budget/variance/page.tsx
Normal file
13
frontend/app/accounting/budget/variance/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تحلیل انحراف بودجه"
|
||||||
|
module="budget"
|
||||||
|
docType="variance"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/approvals/page.tsx
Normal file
13
frontend/app/accounting/compliance/approvals/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گردش تأیید"
|
||||||
|
module="compliance"
|
||||||
|
docType="approval"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/controls/page.tsx
Normal file
13
frontend/app/accounting/compliance/controls/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="کنترلهای داخلی"
|
||||||
|
module="compliance"
|
||||||
|
docType="control"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/policies/page.tsx
Normal file
13
frontend/app/accounting/compliance/policies/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="سیاستها و قوانین"
|
||||||
|
module="compliance"
|
||||||
|
docType="policy"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/records/page.tsx
Normal file
13
frontend/app/accounting/compliance/records/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اسناد و سوابق"
|
||||||
|
module="compliance"
|
||||||
|
docType="record"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/risks/page.tsx
Normal file
13
frontend/app/accounting/compliance/risks/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="مدیریت ریسک"
|
||||||
|
module="compliance"
|
||||||
|
docType="risk"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/sod/page.tsx
Normal file
13
frontend/app/accounting/compliance/sod/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تفکیک وظایف (SoD)"
|
||||||
|
module="compliance"
|
||||||
|
docType="sod"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/compliance/violations/page.tsx
Normal file
13
frontend/app/accounting/compliance/violations/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گزارش تخلفات"
|
||||||
|
module="compliance"
|
||||||
|
docType="violation"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/categories/page.tsx
Normal file
13
frontend/app/accounting/documents/categories/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="دستهبندی اسناد"
|
||||||
|
module="documents"
|
||||||
|
docType="category"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/financial/page.tsx
Normal file
13
frontend/app/accounting/documents/financial/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اسناد مالی"
|
||||||
|
module="documents"
|
||||||
|
docType="financial"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/hr/page.tsx
Normal file
13
frontend/app/accounting/documents/hr/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اسناد پرسنلی"
|
||||||
|
module="documents"
|
||||||
|
docType="hr"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/purchase/page.tsx
Normal file
13
frontend/app/accounting/documents/purchase/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اسناد خرید"
|
||||||
|
module="documents"
|
||||||
|
docType="purchase"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/retention/page.tsx
Normal file
13
frontend/app/accounting/documents/retention/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="نگهداری اسناد"
|
||||||
|
module="documents"
|
||||||
|
docType="retention"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/sales/page.tsx
Normal file
13
frontend/app/accounting/documents/sales/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اسناد فروش"
|
||||||
|
module="documents"
|
||||||
|
docType="sales"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/search/page.tsx
Normal file
13
frontend/app/accounting/documents/search/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="جستجوی اسناد"
|
||||||
|
module="documents"
|
||||||
|
docType="search"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/documents/versions/page.tsx
Normal file
13
frontend/app/accounting/documents/versions/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="نسخههای سند"
|
||||||
|
module="documents"
|
||||||
|
docType="version"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/bank/page.tsx
Normal file
13
frontend/app/accounting/integration/bank/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اتصال بانک"
|
||||||
|
module="integration"
|
||||||
|
docType="bank"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/crm/page.tsx
Normal file
13
frontend/app/accounting/integration/crm/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اتصال CRM"
|
||||||
|
module="integration"
|
||||||
|
docType="crm"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/gateway/page.tsx
Normal file
13
frontend/app/accounting/integration/gateway/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="درگاه پرداخت"
|
||||||
|
module="integration"
|
||||||
|
docType="gateway"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/import-export/page.tsx
Normal file
13
frontend/app/accounting/integration/import-export/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="ورود / خروج داده"
|
||||||
|
module="integration"
|
||||||
|
docType="import_export"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/inventory/page.tsx
Normal file
13
frontend/app/accounting/integration/inventory/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اتصال انبار"
|
||||||
|
module="integration"
|
||||||
|
docType="inventory"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/payroll/page.tsx
Normal file
13
frontend/app/accounting/integration/payroll/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اتصال حقوق"
|
||||||
|
module="integration"
|
||||||
|
docType="payroll"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/reports/page.tsx
Normal file
13
frontend/app/accounting/integration/reports/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گزارش یکپارچگی"
|
||||||
|
module="integration"
|
||||||
|
docType="report"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/integration/webhooks/page.tsx
Normal file
13
frontend/app/accounting/integration/webhooks/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="وبسرویسها"
|
||||||
|
module="integration"
|
||||||
|
docType="webhook"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/adjustments/page.tsx
Normal file
13
frontend/app/accounting/inventory/adjustments/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تعدیل موجودی"
|
||||||
|
module="inventory"
|
||||||
|
docType="adjustment"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
frontend/app/accounting/inventory/items/page.tsx
Normal file
7
frontend/app/accounting/inventory/items/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { InventoryItemsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <InventoryItemsPage />;
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/movements/page.tsx
Normal file
13
frontend/app/accounting/inventory/movements/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گردش کالا"
|
||||||
|
module="inventory"
|
||||||
|
docType="movement"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/receipts-issues/page.tsx
Normal file
13
frontend/app/accounting/inventory/receipts-issues/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="رسید ورود و خروج"
|
||||||
|
module="inventory"
|
||||||
|
docType="receipt_issue"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/reports/page.tsx
Normal file
13
frontend/app/accounting/inventory/reports/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گزارشهای انبار"
|
||||||
|
module="inventory"
|
||||||
|
docType="report"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
frontend/app/accounting/inventory/settings/page.tsx
Normal file
7
frontend/app/accounting/inventory/settings/page.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { WarehousesPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return <WarehousesPage />;
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/transfers/page.tsx
Normal file
13
frontend/app/accounting/inventory/transfers/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="انتقال انبار"
|
||||||
|
module="inventory"
|
||||||
|
docType="transfer"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/inventory/valuation/page.tsx
Normal file
13
frontend/app/accounting/inventory/valuation/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="ارزشگذاری موجودی"
|
||||||
|
module="inventory"
|
||||||
|
docType="valuation"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/activity/page.tsx
Normal file
13
frontend/app/accounting/monitoring/activity/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="فعالیت کاربران"
|
||||||
|
module="monitoring"
|
||||||
|
docType="activity"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/alerts/page.tsx
Normal file
13
frontend/app/accounting/monitoring/alerts/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="هشدارها"
|
||||||
|
module="monitoring"
|
||||||
|
docType="alert"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/health/page.tsx
Normal file
13
frontend/app/accounting/monitoring/health/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="وضعیت سرویس"
|
||||||
|
module="monitoring"
|
||||||
|
docType="health"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/kpis/page.tsx
Normal file
13
frontend/app/accounting/monitoring/kpis/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="شاخصهای کلیدی"
|
||||||
|
module="monitoring"
|
||||||
|
docType="kpi"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/page.tsx
Normal file
13
frontend/app/accounting/monitoring/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="داشبورد نظارتی"
|
||||||
|
module="monitoring"
|
||||||
|
docType="dashboard"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/performance/page.tsx
Normal file
13
frontend/app/accounting/monitoring/performance/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="عملکرد سیستم"
|
||||||
|
module="monitoring"
|
||||||
|
docType="performance"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/monitoring/recent/page.tsx
Normal file
13
frontend/app/accounting/monitoring/recent/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="عملیات اخیر"
|
||||||
|
module="monitoring"
|
||||||
|
docType="recent"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/allocation/page.tsx
Normal file
13
frontend/app/accounting/payroll/allocation/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تسهیم هزینه حقوق"
|
||||||
|
module="payroll"
|
||||||
|
docType="allocation"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
5
frontend/app/accounting/payroll/calculate/page.tsx
Normal file
5
frontend/app/accounting/payroll/calculate/page.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
redirect("/accounting/payroll");
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/contracts/page.tsx
Normal file
13
frontend/app/accounting/payroll/contracts/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تعریف قرارداد"
|
||||||
|
module="payroll"
|
||||||
|
docType="contract"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/employees/page.tsx
Normal file
13
frontend/app/accounting/payroll/employees/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="کارمندان"
|
||||||
|
module="payroll"
|
||||||
|
docType="employee"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/items/page.tsx
Normal file
13
frontend/app/accounting/payroll/items/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اقلام حقوق و مزایا"
|
||||||
|
module="payroll"
|
||||||
|
docType="pay_item"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/payments/page.tsx
Normal file
13
frontend/app/accounting/payroll/payments/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پرداخت حقوق"
|
||||||
|
module="payroll"
|
||||||
|
docType="payment"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/reports/page.tsx
Normal file
13
frontend/app/accounting/payroll/reports/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="گزارشهای حقوق"
|
||||||
|
module="payroll"
|
||||||
|
docType="report"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/payroll/structures/page.tsx
Normal file
13
frontend/app/accounting/payroll/structures/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="ساختار حقوق"
|
||||||
|
module="payroll"
|
||||||
|
docType="structure"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/goods-receipts/page.tsx
Normal file
13
frontend/app/accounting/purchase/goods-receipts/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="رسید کالا"
|
||||||
|
module="purchase"
|
||||||
|
docType="goods_receipt"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/invoices/page.tsx
Normal file
13
frontend/app/accounting/purchase/invoices/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="فاکتور خرید"
|
||||||
|
module="purchase"
|
||||||
|
docType="invoice"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/orders/page.tsx
Normal file
13
frontend/app/accounting/purchase/orders/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="سفارش خرید"
|
||||||
|
module="purchase"
|
||||||
|
docType="order"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/prepayments/page.tsx
Normal file
13
frontend/app/accounting/purchase/prepayments/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پیشپرداختها"
|
||||||
|
module="purchase"
|
||||||
|
docType="prepayment"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/requests/page.tsx
Normal file
13
frontend/app/accounting/purchase/requests/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="درخواست خرید"
|
||||||
|
module="purchase"
|
||||||
|
docType="request"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/returns/page.tsx
Normal file
13
frontend/app/accounting/purchase/returns/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="مرجوعی خرید"
|
||||||
|
module="purchase"
|
||||||
|
docType="return"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/purchase/settlements/page.tsx
Normal file
13
frontend/app/accounting/purchase/settlements/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تسویه با تأمینکننده"
|
||||||
|
module="purchase"
|
||||||
|
docType="settlement"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,11 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState, Suspense } from "react";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { accountingApi } from "@/lib/accounting-api";
|
import { accountingApi } from "@/lib/accounting-api";
|
||||||
import { useTenantId } from "@/hooks/useTenantId";
|
import { useTenantId } from "@/hooks/useTenantId";
|
||||||
import { formatMoney } from "@/lib/utils";
|
import { formatMoney } from "@/lib/utils";
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
import {
|
import {
|
||||||
PageHeader,
|
PageHeader,
|
||||||
Button,
|
Button,
|
||||||
@ -30,6 +32,14 @@ const LABELS: Record<ReportKind, string> = {
|
|||||||
"income-statement": "سود و زیان",
|
"income-statement": "سود و زیان",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const OPS_REPORTS: Record<string, { title: string; module: string; docType: string }> = {
|
||||||
|
"cash-flow": { title: "جریان وجوه نقد", module: "reports", docType: "cash_flow" },
|
||||||
|
equity: { title: "تغییرات حقوق صاحبان سهام", module: "reports", docType: "equity" },
|
||||||
|
subsidiary: { title: "گزارش معین", module: "reports", docType: "subsidiary" },
|
||||||
|
detail: { title: "گزارش تفصیلی", module: "reports", docType: "detail" },
|
||||||
|
analytical: { title: "گزارش تحلیلی", module: "reports", docType: "analytical" },
|
||||||
|
};
|
||||||
|
|
||||||
const FIELD_LABELS: Record<string, string> = {
|
const FIELD_LABELS: Record<string, string> = {
|
||||||
total_debit: "جمع بدهکار",
|
total_debit: "جمع بدهکار",
|
||||||
total_credit: "جمع بستانکار",
|
total_credit: "جمع بستانکار",
|
||||||
@ -66,7 +76,7 @@ function formatCellValue(key: string, value: unknown): React.ReactNode {
|
|||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ReportsPage() {
|
function EngineReports({ initialKind }: { initialKind?: string }) {
|
||||||
const { tenantId } = useTenantId();
|
const { tenantId } = useTenantId();
|
||||||
const [periodId, setPeriodId] = useState("");
|
const [periodId, setPeriodId] = useState("");
|
||||||
const [result, setResult] = useState<{ kind: ReportKind; payload: { id: string; data: unknown } } | null>(
|
const [result, setResult] = useState<{ kind: ReportKind; payload: { id: string; data: unknown } } | null>(
|
||||||
@ -105,10 +115,7 @@ export default function ReportsPage() {
|
|||||||
accountingApi.reporting.export(tenantId!, result!.payload.id, format),
|
accountingApi.reporting.export(tenantId!, result!.payload.id, format),
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
toast.success(`خروجی ${data.format} ثبت شد`);
|
toast.success(`خروجی ${data.format} ثبت شد`);
|
||||||
if (data.file_path) {
|
if (data.file_path) toast.message(data.file_path);
|
||||||
toast.message(data.file_path);
|
|
||||||
}
|
|
||||||
// Download client-side JSON snapshot for immediate UX
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const blob = new Blob([JSON.stringify(result.payload, null, 2)], {
|
const blob = new Blob([JSON.stringify(result.payload, null, 2)], {
|
||||||
type: "application/json",
|
type: "application/json",
|
||||||
@ -144,6 +151,13 @@ export default function ReportsPage() {
|
|||||||
return <ErrorState message={periodsQ.error.message} onRetry={() => periodsQ.refetch()} />;
|
return <ErrorState message={periodsQ.error.message} onRetry={() => periodsQ.refetch()} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const highlight =
|
||||||
|
initialKind === "trial-balance" ||
|
||||||
|
initialKind === "balance-sheet" ||
|
||||||
|
initialKind === "income-statement"
|
||||||
|
? (initialKind as ReportKind)
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
@ -168,7 +182,7 @@ export default function ReportsPage() {
|
|||||||
<Button
|
<Button
|
||||||
key={kind}
|
key={kind}
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant={highlight === kind ? "default" : "outline"}
|
||||||
disabled={runM.isPending || !periodId}
|
disabled={runM.isPending || !periodId}
|
||||||
onClick={() => runM.mutate(kind)}
|
onClick={() => runM.mutate(kind)}
|
||||||
>
|
>
|
||||||
@ -233,3 +247,21 @@ export default function ReportsPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ReportsRouter() {
|
||||||
|
const sp = useSearchParams();
|
||||||
|
const type = sp.get("type") || "";
|
||||||
|
const ops = OPS_REPORTS[type];
|
||||||
|
if (ops) {
|
||||||
|
return <BusinessDocsPage title={ops.title} module={ops.module} docType={ops.docType} />;
|
||||||
|
}
|
||||||
|
return <EngineReports initialKind={type || undefined} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ReportsPage() {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<LoadingState />}>
|
||||||
|
<ReportsRouter />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
13
frontend/app/accounting/sales/invoices/page.tsx
Normal file
13
frontend/app/accounting/sales/invoices/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="فاکتور فروش"
|
||||||
|
module="sales"
|
||||||
|
docType="invoice"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/opportunities/page.tsx
Normal file
13
frontend/app/accounting/sales/opportunities/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="فرصتهای فروش"
|
||||||
|
module="sales"
|
||||||
|
docType="opportunity"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/orders/page.tsx
Normal file
13
frontend/app/accounting/sales/orders/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="سفارش فروش"
|
||||||
|
module="sales"
|
||||||
|
docType="order"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/pre-receipts/page.tsx
Normal file
13
frontend/app/accounting/sales/pre-receipts/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پیشدریافتها"
|
||||||
|
module="sales"
|
||||||
|
docType="pre_receipt"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/proformas/page.tsx
Normal file
13
frontend/app/accounting/sales/proformas/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پیشفاکتور"
|
||||||
|
module="sales"
|
||||||
|
docType="proforma"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/returns/page.tsx
Normal file
13
frontend/app/accounting/sales/returns/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="مرجوعی فروش"
|
||||||
|
module="sales"
|
||||||
|
docType="return"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/sales/settlements/page.tsx
Normal file
13
frontend/app/accounting/sales/settlements/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تسویه حساب مشتریان"
|
||||||
|
module="sales"
|
||||||
|
docType="settlement"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/settings/backup/page.tsx
Normal file
13
frontend/app/accounting/settings/backup/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="پشتیبانگیری"
|
||||||
|
module="settings"
|
||||||
|
docType="backup"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/settings/company/page.tsx
Normal file
13
frontend/app/accounting/settings/company/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="اطلاعات شرکت"
|
||||||
|
module="settings"
|
||||||
|
docType="company"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/settings/general/page.tsx
Normal file
13
frontend/app/accounting/settings/general/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تنظیمات عمومی"
|
||||||
|
module="settings"
|
||||||
|
docType="general"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/app/accounting/settings/tax/page.tsx
Normal file
13
frontend/app/accounting/settings/tax/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { BusinessDocsPage } from "@/components/accounting/BusinessDocsPage";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<BusinessDocsPage
|
||||||
|
title="تنظیمات مالیاتی"
|
||||||
|
module="settings"
|
||||||
|
docType="tax"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -49,7 +49,7 @@ const STEP_LINKS = {
|
|||||||
has_base_currency: { href: "/accounting/currencies", label: "ارز پایه" },
|
has_base_currency: { href: "/accounting/currencies", label: "ارز پایه" },
|
||||||
has_fiscal_year: { href: "/accounting/fiscal", label: "سال مالی" },
|
has_fiscal_year: { href: "/accounting/fiscal", label: "سال مالی" },
|
||||||
has_fiscal_period: { href: "/accounting/fiscal", label: "دوره مالی" },
|
has_fiscal_period: { href: "/accounting/fiscal", label: "دوره مالی" },
|
||||||
has_cash_box: { href: "/accounting/treasury", label: "صندوق" },
|
has_cash_box: { href: "/accounting/treasury/cash-boxes", label: "صندوق" },
|
||||||
has_customer: { href: "/accounting/customers", label: "مشتری" },
|
has_customer: { href: "/accounting/customers", label: "مشتری" },
|
||||||
has_voucher: { href: "/accounting/vouchers", label: "سند حسابداری" },
|
has_voucher: { href: "/accounting/vouchers", label: "سند حسابداری" },
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user