feat: implement complete CMT backend with API endpoints and test suite

- Add 7 core API endpoints: users, transactions, partners, products, inventory, payments, credit
- Implement role-based authentication (admin/write/read-only access)
- Add comprehensive database models with proper relationships
- Include full test coverage for all endpoints and business logic
- Set up Alembic migrations and Docker configuration
- Configure FastAPI app with CORS and database integration
This commit is contained in:
2025-09-14 21:04:07 +02:00
parent 49c813778b
commit c086f64363
48 changed files with 6992 additions and 126 deletions
+184 -15
View File
@@ -2,40 +2,209 @@
Custom validation schema
"""
from sqlmodel import SQLModel
from app.schemas.base import UserRole, PartnerType, PaymentMethod
from typing import Optional
from datetime import datetime, date
from .base import TransactionType, TransactionStatus
class ClientCreate(SQLModel):
######################################################
# Users
class UserCreate(SQLModel):
username: str
password: str
role: UserRole = UserRole.READ_ONLY
class UserUpdate(SQLModel):
username: Optional[str] = None
password: Optional[str] = None
role: Optional[UserRole] = None
class UserLogin(SQLModel):
username: str
password: str
class UserResponse(SQLModel):
id: Optional[int] = None
username: str
role: UserRole
class Token(SQLModel):
access_token: str
token_type: str
expires_in: int
user: UserResponse
class TokenData(SQLModel):
username: Optional[str] = None
user_id: Optional[int] = None
role: Optional[UserRole] = None
##################################################
# Transactions
class TransactionBase(SQLModel):
partner_id: int
transcation_type: TransactionType = TransactionType.SALE
transaction_status: TransactionStatus = TransactionStatus.UNPAID
total_amount: int
class TransactionCreate(TransactionBase):
pass
class TransactionUpdate(SQLModel):
partner_id: Optional[int] = None
transcation_type: Optional[TransactionType] = None
transaction_status: Optional[TransactionStatus] = None
total_amount: Optional[int] = None
class TransactionResponse(TransactionBase):
id: int
created_by: int
updated_by: int
created_on: datetime
updated_on: datetime
##################################################
# Partners
class PartnerBase(SQLModel):
tin_number: int
names: str
phone_number: str
class ClientUpdate(SQLModel):
tin_number: Optional[int] = None
names: Optional[str] = None
type: PartnerType = PartnerType.CLIENT
phone_number: Optional[str] = None
class PartnerCreate(PartnerBase):
pass
class SupplierCreate(SQLModel):
tin_number: int
names: str
phone_number: str
class SupplierUpdate(ClientUpdate):
class PartnerUpdate(SQLModel):
tin_number: Optional[int] = None
names: Optional[str] = None
type: Optional[PartnerType] = None
phone_number: Optional[str] = None
class PartnerResponse(PartnerBase):
id: int
class ProductCreate(SQLModel):
##################################################
# Products
class ProductBase(SQLModel):
product_code: str
product_name: str
purchase_price: int
selling_price: int
class ProductCreate(ProductBase):
pass
class ProductUpdate(SQLModel):
product_code: Optional[str] = None
product_name: Optional[str] = None
purchase_price: Optional[int] = None
selling_price: Optional[int] = None
class ProductResponse(ProductBase):
id: int
date_modified: datetime
##################################################
# Transaction Details
class TransactionDetailsBase(SQLModel):
partner_id: int
product_id: int
qty: int
selling_price: int
total_value: int
class TransactionDetailsCreate(TransactionDetailsBase):
pass
class TransactionDetailsUpdate(SQLModel):
partner_id: Optional[int] = None
product_id: Optional[int] = None
qty: Optional[int] = None
selling_price: Optional[int] = None
total_value: Optional[int] = None
class TransactionDetailsResponse(TransactionDetailsBase):
id: int
created_by: int
updated_by: int
created_at: datetime
updated_at: datetime
##################################################
# Payments
class PaymentBase(SQLModel):
transaction_id: int
payment_method: PaymentMethod = PaymentMethod.CASH
paid_amount: int
payment_date: date
class PaymentCreate(PaymentBase):
pass
class PaymentUpdate(SQLModel):
transaction_id: Optional[int] = None
payment_method: Optional[PaymentMethod] = None
paid_amount: Optional[int] = None
payment_date: Optional[date] = None
class PaymentResponse(PaymentBase):
id: int
created_by: int
updated_by: int
created_at: datetime
updated_at: datetime
##################################################
# Credit
class CreditBase(SQLModel):
partner_id: int
transaction_id: int
credit_amount: int
credit_limit: int
balance: int
class CreditCreate(CreditBase):
pass
class CreditUpdate(SQLModel):
partner_id: Optional[int] = None
transaction_id: Optional[int] = None
credit_amount: Optional[int] = None
credit_limit: Optional[int] = None
balance: Optional[int] = None
class CreditResponse(CreditBase):
id: int
created_by: int
updated_by: int
created_at: datetime
updated_at: datetime
##################################################
# Inventory
class InventoryBase(SQLModel):
product_id: int
total_qty: int
class InventoryCreate(InventoryBase):
pass
class InventoryUpdate(SQLModel):
product_id: Optional[int] = None
total_qty: Optional[int] = None
class InventoryResponse(InventoryBase):
id: int