from __future__ import annotations from sqlalchemy import JSON, BigInteger, Boolean, Date, DateTime, DECIMAL, ForeignKey, Index, Integer, String, Text, text from sqlalchemy.orm import Mapped, mapped_column from app.models.base import Base class MiniAppAttendancePoint(Base): __tablename__ = "attendance_points" name: Mapped[str] = mapped_column(String(128), primary_key=True) latitude: Mapped[float | None] = mapped_column(DECIMAL(10, 7), nullable=True) longitude: Mapped[float | None] = mapped_column(DECIMAL(10, 7), nullable=True) radius_meters: Mapped[int] = mapped_column(Integer, server_default=text("500")) day_start: Mapped[str] = mapped_column(String(5), server_default=text("'08:00'")) day_end: Mapped[str] = mapped_column(String(5), server_default=text("'17:20'")) lunch_start: Mapped[str] = mapped_column(String(5), server_default=text("'11:40'")) lunch_end: Mapped[str] = mapped_column(String(5), server_default=text("'12:40'")) dinner_start: Mapped[str] = mapped_column(String(5), server_default=text("'17:20'")) dinner_end: Mapped[str] = mapped_column(String(5), server_default=text("'18:00'")) overtime_start: Mapped[str] = mapped_column(String(5), server_default=text("'18:00'")) overtime_end: Mapped[str] = mapped_column(String(5), server_default=text("'20:00'")) night_start: Mapped[str] = mapped_column(String(5), server_default=text("'20:00'")) night_end: Mapped[str] = mapped_column(String(5), server_default=text("'06:00'")) remark: Mapped[str | None] = mapped_column(String(500), nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, server_default=text("1")) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) class MiniAppPersonnel(Base): __tablename__ = "personnel" phone: Mapped[str] = mapped_column(String(20), primary_key=True) name: Mapped[str] = mapped_column(String(64)) is_temporary: Mapped[bool] = mapped_column(Boolean, server_default=text("0")) temporary_expires_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) class MiniAppPersonRole(Base): __tablename__ = "person_roles" phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone"), primary_key=True) role: Mapped[str] = mapped_column(String(32), primary_key=True) created_at: Mapped[object] = mapped_column(DateTime) class MiniAppPersonAttendancePoint(Base): __tablename__ = "person_attendance_points" phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone"), primary_key=True) attendance_point_name: Mapped[str] = mapped_column(ForeignKey("attendance_points.name"), primary_key=True) created_at: Mapped[object] = mapped_column(DateTime) class MiniAppProduct(Base): __tablename__ = "products" attendance_point_name: Mapped[str] = mapped_column(String(128), primary_key=True, server_default=text("''")) project_no: Mapped[str] = mapped_column(String(64), primary_key=True) product_name: Mapped[str] = mapped_column(String(255), primary_key=True) device_no: Mapped[str] = mapped_column(String(64), primary_key=True) process_name: Mapped[str] = mapped_column(String(128), primary_key=True) profile_no: Mapped[str | None] = mapped_column(String(128), nullable=True) material_code: Mapped[str | None] = mapped_column(String(128), nullable=True) material_name: Mapped[str | None] = mapped_column(String(255), nullable=True) supplier: Mapped[str | None] = mapped_column(String(255), nullable=True) product_net_weight_kg: Mapped[float | None] = mapped_column(DECIMAL(12, 4), nullable=True) product_gross_weight_kg: Mapped[float | None] = mapped_column(DECIMAL(12, 4), nullable=True) scrap_loss_rate: Mapped[float | None] = mapped_column(DECIMAL(10, 6), nullable=True) waste_price_yuan_per_kg: Mapped[float | None] = mapped_column(DECIMAL(12, 4), nullable=True) stamping_method: Mapped[str | None] = mapped_column(String(128), nullable=True) operator_count: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("1")) process_unit_price_yuan: Mapped[float] = mapped_column(DECIMAL(12, 4), server_default=text("0")) standard_beat: Mapped[float] = mapped_column(DECIMAL(12, 3), server_default=text("0")) standard_workload: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_products_device_no", "device_no"), Index("idx_products_material_code", "material_code"), ) class MiniAppEquipment(Base): __tablename__ = "equipment" attendance_point_name: Mapped[str] = mapped_column(String(128), primary_key=True, server_default=text("''")) device_no: Mapped[str] = mapped_column(String(64), primary_key=True) device_type: Mapped[str] = mapped_column(String(32), server_default=text("'冲压设备'")) remark: Mapped[str | None] = mapped_column(String(500), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) class MiniAppWorkSchedule(Base): __tablename__ = "work_schedules" id: Mapped[int] = mapped_column(Integer, primary_key=True, server_default=text("1")) day_start: Mapped[str] = mapped_column(String(5), server_default=text("'08:00'")) day_end: Mapped[str] = mapped_column(String(5), server_default=text("'17:20'")) lunch_start: Mapped[str] = mapped_column(String(5), server_default=text("'11:40'")) lunch_end: Mapped[str] = mapped_column(String(5), server_default=text("'12:40'")) dinner_start: Mapped[str] = mapped_column(String(5), server_default=text("'17:20'")) dinner_end: Mapped[str] = mapped_column(String(5), server_default=text("'18:00'")) overtime_start: Mapped[str] = mapped_column(String(5), server_default=text("'18:00'")) overtime_end: Mapped[str] = mapped_column(String(5), server_default=text("'20:00'")) night_start: Mapped[str] = mapped_column(String(5), server_default=text("'20:00'")) night_end: Mapped[str] = mapped_column(String(5), server_default=text("'06:00'")) attendance_latitude: Mapped[float | None] = mapped_column(DECIMAL(10, 7), nullable=True) attendance_longitude: Mapped[float | None] = mapped_column(DECIMAL(10, 7), nullable=True) attendance_radius_meters: Mapped[int] = mapped_column(Integer, server_default=text("500")) auto_submit_hours: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("15")) updated_by: Mapped[str | None] = mapped_column(String(20), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) class MiniAppWorkSession(Base): __tablename__ = "work_sessions" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) attendance_point_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) employee_phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) start_at: Mapped[object] = mapped_column(DateTime) end_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) status: Mapped[str] = mapped_column(String(32), server_default=text("'active'")) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_sessions_employee_status", "employee_phone", "status"), ) class MiniAppWorkSessionDevice(Base): __tablename__ = "work_session_devices" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) session_id: Mapped[int] = mapped_column(ForeignKey("work_sessions.id")) attendance_point_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) device_no: Mapped[str] = mapped_column(String(255)) process_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) scanned_at: Mapped[object] = mapped_column(DateTime) sort_order: Mapped[int] = mapped_column(Integer, server_default=text("0")) released_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) released_by: Mapped[str | None] = mapped_column(String(20), nullable=True) release_reason: Mapped[str | None] = mapped_column(String(120), nullable=True) __table_args__ = ( Index("idx_session_devices_session", "session_id"), Index("idx_session_devices_device", "device_no"), Index("idx_session_devices_release", "released_at"), ) class MiniAppProductionReport(Base): __tablename__ = "production_reports" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) attendance_point_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) session_id: Mapped[int] = mapped_column(ForeignKey("work_sessions.id"), unique=True) employee_phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) report_date: Mapped[object] = mapped_column(Date) start_at: Mapped[object] = mapped_column(DateTime) end_at: Mapped[object] = mapped_column(DateTime) duration_minutes: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) break_minutes: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) effective_minutes: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) total_good_qty: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) total_output_qty: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) actual_beat: Mapped[float] = mapped_column(DECIMAL(12, 3), server_default=text("0")) standard_beat: Mapped[float] = mapped_column(DECIMAL(12, 3), server_default=text("0")) expected_workload: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) pace_rate: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) workload_rate: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) status: Mapped[str] = mapped_column(String(32), server_default=text("'pending'")) reviewer_phone: Mapped[str | None] = mapped_column(String(20), nullable=True) reviewed_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) reject_reason: Mapped[str | None] = mapped_column(String(500), nullable=True) review_remark: Mapped[str | None] = mapped_column(String(500), nullable=True) submitted_at: Mapped[object] = mapped_column(DateTime) is_system_auto_submitted: Mapped[bool] = mapped_column(Boolean, server_default=text("0")) auto_submit_reason: Mapped[str | None] = mapped_column(String(120), nullable=True) is_multi_person_assistant: Mapped[bool] = mapped_column(Boolean, server_default=text("0")) multi_person_source_report_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True) is_voided: Mapped[bool] = mapped_column(Boolean, server_default=text("0")) voided_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) voided_by: Mapped[str | None] = mapped_column(ForeignKey("personnel.phone"), nullable=True) unvoid_deadline_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) updated_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_reports_employee_date", "employee_phone", "report_date"), Index("idx_reports_status_date", "status", "report_date"), Index("idx_reports_reviewer", "reviewer_phone", "reviewed_at"), Index("idx_reports_voided", "is_voided", "voided_at"), ) class MiniAppProductionReportItem(Base): __tablename__ = "production_report_items" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) report_id: Mapped[int] = mapped_column(ForeignKey("production_reports.id")) attendance_point_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) device_no: Mapped[str] = mapped_column(String(64)) project_no: Mapped[str] = mapped_column(String(64)) product_name: Mapped[str] = mapped_column(String(255)) material_code: Mapped[str | None] = mapped_column(String(128), nullable=True) material_name: Mapped[str | None] = mapped_column(String(255), nullable=True) raw_material_batch_no: Mapped[str | None] = mapped_column(String(128), nullable=True) process_name: Mapped[str | None] = mapped_column(String(128), nullable=True) stamping_method: Mapped[str | None] = mapped_column(String(128), nullable=True) operator_count: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("1")) process_unit_price_yuan: Mapped[float] = mapped_column(DECIMAL(12, 4), server_default=text("0")) standard_beat: Mapped[float] = mapped_column(DECIMAL(12, 3), server_default=text("0")) standard_workload: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) good_qty: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) defect_qty: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) scrap_qty: Mapped[float] = mapped_column(DECIMAL(12, 2), server_default=text("0")) allocated_minutes: Mapped[float] = mapped_column(DECIMAL(10, 2), server_default=text("0")) started_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) remark: Mapped[str | None] = mapped_column(String(500), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_report_items_report", "report_id"), Index("idx_report_items_product", "project_no", "product_name"), ) class MiniAppReportAuditLog(Base): __tablename__ = "report_audit_logs" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) report_id: Mapped[int] = mapped_column(ForeignKey("production_reports.id")) reviewer_phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) action: Mapped[str] = mapped_column(String(64)) before_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) after_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) remark: Mapped[str | None] = mapped_column(String(500), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_audit_report", "report_id"), Index("idx_audit_reviewer", "reviewer_phone", "created_at"), ) class MiniAppMoldLockFeedback(Base): __tablename__ = "mold_lock_feedbacks" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) attendance_point_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) mold_name: Mapped[str] = mapped_column(String(255)) process_name: Mapped[str] = mapped_column(String(128), server_default=text("''")) session_device_id: Mapped[int] = mapped_column(ForeignKey("work_session_devices.id")) reporter_phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) occupied_phone: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) status: Mapped[str] = mapped_column(String(32), server_default=text("'pending'")) read_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) handled_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) handled_by: Mapped[str | None] = mapped_column(ForeignKey("personnel.phone"), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_mold_lock_feedback_point_read", "attendance_point_name", "read_at", "created_at"), Index("idx_mold_lock_feedback_status", "status", "created_at"), ) class MiniAppDeviceQRCode(Base): __tablename__ = "device_qrcodes" attendance_point_name: Mapped[str] = mapped_column(String(128), primary_key=True, server_default=text("''")) device_no: Mapped[str] = mapped_column(String(255), primary_key=True) process_name: Mapped[str] = mapped_column(String(128), primary_key=True, server_default=text("''")) qr_scene: Mapped[str] = mapped_column(String(128)) qr_url: Mapped[str | None] = mapped_column(String(500), nullable=True) created_by: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) created_at: Mapped[object] = mapped_column(DateTime) class MiniAppDeviceQRCodeBatchTask(Base): __tablename__ = "device_qrcode_batch_tasks" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) file_name: Mapped[str] = mapped_column(String(255)) status: Mapped[str] = mapped_column(String(32), server_default=text("'pending'")) item_count: Mapped[int] = mapped_column(Integer, server_default=text("0")) completed_count: Mapped[int] = mapped_column(Integer, server_default=text("0")) failed_count: Mapped[int] = mapped_column(Integer, server_default=text("0")) items_json: Mapped[list] = mapped_column(JSON) zip_url: Mapped[str | None] = mapped_column(String(500), nullable=True) error_message: Mapped[str | None] = mapped_column(String(1000), nullable=True) created_by: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) started_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) finished_at: Mapped[object | None] = mapped_column(DateTime, nullable=True) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_device_qrcode_batch_tasks_creator", "created_by", "created_at"), Index("idx_device_qrcode_batch_tasks_status", "status", "created_at"), ) class MiniAppNotice(Base): __tablename__ = "notices" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True) title: Mapped[str] = mapped_column(String(120)) content: Mapped[str] = mapped_column(Text) sort_order: Mapped[int] = mapped_column(Integer, server_default=text("0")) is_active: Mapped[bool] = mapped_column(Boolean, server_default=text("1")) created_by: Mapped[str] = mapped_column(ForeignKey("personnel.phone")) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) class MiniAppNoticePoint(Base): __tablename__ = "notice_points" notice_id: Mapped[int] = mapped_column(ForeignKey("notices.id"), primary_key=True) attendance_point_name: Mapped[str] = mapped_column(ForeignKey("attendance_points.name"), primary_key=True) created_at: Mapped[object] = mapped_column(DateTime) class MiniAppReconciliationLedgerEntry(Base): __tablename__ = "reconciliation_ledger_entries" attendance_point_name: Mapped[str] = mapped_column(String(128), primary_key=True, server_default=text("''")) year: Mapped[int] = mapped_column(Integer, primary_key=True) month: Mapped[int] = mapped_column(Integer, primary_key=True) product_name: Mapped[str] = mapped_column(String(255), primary_key=True) reconciled_good_qty: Mapped[float] = mapped_column(DECIMAL(14, 2), server_default=text("0")) return_qty: Mapped[float] = mapped_column(DECIMAL(14, 2), server_default=text("0")) updated_by: Mapped[str | None] = mapped_column(String(20), nullable=True) created_at: Mapped[object] = mapped_column(DateTime) updated_at: Mapped[object] = mapped_column(DateTime) __table_args__ = ( Index("idx_reconciliation_product", "product_name"), Index("idx_reconciliation_updated", "updated_at"), )