Files
server-core/app/incubator/routers.py
T
Pine 86c6d24b17 fix(pay): 所有支付小程序码 page 路径修正为 pages-extra 子包路径
统一修正3处支付相关小程序码的 page 参数(之前误写为主包 pages/ 路径,
扫码后微信找不到页面→白屏):

- app/pay/service.py: 算力充值支付 → pages-extra/pay/index
- app/market/service.py: 市场购买支付 → pages-extra/pay/index
- app/training/main.py: 活动报名支付 → pages-extra/pay-qr/index

加上之前修复的 scan-login(auth.py + wechat.py 默认参数),
后端所有 get_wxacode 调用的 page 路径现已全部正确。
2026-09-02 11:47:34 +08:00

664 lines
27 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""创业园运营子应用接口层(app/incubator)—— 月度报告 / 共享区域 / 使用申请。
- 认证:平台 JWTget_current_user),复用主应用登录态。
- 身份:service.resolve_identity 判定管理方 / 提交方(管理方 carrier 或权限码;
提交方=园区入驻企业成员)。
- 数据归属:管理方=全园区(按 tenant_id),提交方=本企业(按 company_id)。
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from ..api.dependencies import Database, get_current_user, get_db
from . import service
from .service import resolve_identity
logger = logging.getLogger("incubator.api")
router = APIRouter(prefix="/incubator", tags=["incubator"])
# ---------------------------------------------------------------------------
# 请求模型
# ---------------------------------------------------------------------------
class ReportCreateRequest(BaseModel):
report_month: str = Field(..., description="报告月份,如 2026-08")
company_name: str = ""
zone: str = "" # 孵化区域
unit_no: str = "" # 单元号
park_entry_date: str = "" # 入园时间
leader_name: str = "" # 负责人姓名
registered_at: str = "" # 注册时间
registered_capital_wan: float | None = None
credit_code: str = ""
rd_invest_wan: float | None = None
month_revenue_wan: float | None = None
avg_year_revenue_wan: float | None = None
month_gross_profit_wan: float | None = None
month_tax_wan: float | None = None
avg_year_tax_wan: float | None = None
loan_startup_wan: float | None = None
loan_yunling_wan: float | None = None
contest_award_wan: float | None = None
patents: int | None = None
jobs_created: int | None = None
team: list = Field(default_factory=list)
business_note: str = ""
suggestion: str = ""
filler_name: str = ""
filler_email: str = ""
class ReportUpdateRequest(ReportCreateRequest):
_force_reopen: bool = False
class ReviewReportRequest(BaseModel):
action: str = Field(..., description="approve|reject")
comment: str = ""
class AreaCreateRequest(BaseModel):
name: str = Field(..., description="区域名称")
area_type: str = Field("meeting", description="live|meeting")
location: str = ""
capacity: int | None = None
facilities: list = Field(default_factory=list)
cover_url: str = ""
open_hour_start: str = "09:00"
open_hour_end: str = "18:00"
max_minutes: int | None = None
enabled: bool = True
status: str = Field("normal", description="normal|maintenance|closed 运营标记")
status_note: str = "" # 标记说明(如"设备检修中")
class AreaUpdateRequest(AreaCreateRequest):
pass
class ReservationCreateRequest(BaseModel):
area_id: str = Field(..., description="共享区域 id")
start_at: str = Field(..., description="使用日期起 YYYY-MM-DD HH:MM")
end_at: str = Field(..., description="使用日期止 YYYY-MM-DD HH:MM(支持跨天)")
attendees: int | None = None
purpose: str = Field("meeting", description="activity|meeting 用途(活动|会议)")
leader_name: str = ""
leader_phone: str = ""
contact_name: str = ""
contact_phone: str = ""
agreed_commitment: bool = False
signer_name: str = ""
company_name: str = ""
company_id: str = "" # 管理方代申请时指定
class ReviewReservationRequest(BaseModel):
action: str = Field(..., description="approve|reject")
comment: str = ""
record_received: bool = False # 备案:已接收备案
record_safety_notified: bool = False # 备案:已告知安全注意事项
record_handler: str = "" # 备案经办人
class SettingsUpdateRequest(BaseModel):
reservation_notice: str = "" # 共享区域申请注意事项/须知
report_notice: str = "" # 月报填报说明
open_summary: str = "" # 开放区域总览说明
# ---------------------------------------------------------------------------
# 公共:身份 / 概览
# ---------------------------------------------------------------------------
@router.get("/me", summary="当前身份(提交方/管理方/所属企业)")
async def incubator_me(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager and not ident.company_id:
return {"identity": None,
"message": "当前账号不属于昆明市大学生创业园:非本园入驻企业成员,也非本园管理员,请联系园区管理员绑定"}
return {"identity": ident.to_dict()}
@router.get("/overview", summary="首页概览(报告状态 / 我的申请 / 园区统计)")
async def incubator_overview(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
service.require_identity(ident)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
from datetime import datetime
this_month = datetime.now().strftime("%Y-%m")
report_rows = await service.list_reports(db, ident, month=this_month, page_size=1)
report = report_rows["items"][0] if report_rows["items"] else None
my_res = await service.list_reservations(db, ident, page_size=5)
stats = await service.report_stats(db, ident, month=this_month) if ident.is_manager else None
return {
"identity": ident.to_dict(),
"this_month": this_month,
"my_report": report,
"my_reservations": my_res["items"],
"stats": stats,
}
# ---------------------------------------------------------------------------
# 月度报告
# ---------------------------------------------------------------------------
@router.get("/reports", summary="报告列表(管理方=全园区,提交方=本企业)")
async def incubator_reports(
month: str = "", status: str = "",
page: int = 1, page_size: int = 50,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.list_reports(db, ident, month=month, status=status,
page=page, page_size=page_size)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.get("/reports/stats", summary="报告统计(管理方)")
async def incubator_report_stats(
month: str = "",
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.report_stats(db, ident, month=month)
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.get("/reports/export", summary="导出报告 CSV(管理方,统计表列)")
async def incubator_reports_export(
month: str = "",
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager:
raise HTTPException(status_code=403, detail="仅管理方可导出")
rows = (await service.list_reports(db, ident, month=month, page_size=10000))["items"]
import io
import csv
buf = io.StringIO()
w = csv.writer(buf)
w.writerow(["报告月份", "孵化区域", "单元号", "企业名称", "入园时间", "负责人",
"注册时间", "注册资金(万)", "统一信用代码", "研发当月投入(万)",
"当月营业额(万)", "年平均营业额(万)", "当月毛利润(万)", "当月缴税(万)",
"年平均缴税(万)", "创业担保贷款(万)", "云岭创业贷款(万)",
"创业大赛扶持(万)", "专利(项)", "带动就业人数", "经营状况",
"建议意见", "填表人", "填表邮箱", "状态", "审核意见"])
for r in rows:
w.writerow([r["report_month"], r["zone"], r["unit_no"], r["company_name"],
r["park_entry_date"], r["leader_name"], r["registered_at"],
r["registered_capital_wan"], r["credit_code"], r["rd_invest_wan"],
r["month_revenue_wan"], r["avg_year_revenue_wan"],
r["month_gross_profit_wan"], r["month_tax_wan"],
r["avg_year_tax_wan"], r["loan_startup_wan"], r["loan_yunling_wan"],
r["contest_award_wan"], r["patents"], r["jobs_created"],
r["business_note"], r["suggestion"], r["filler_name"],
r["filler_email"], r["status"], r["review_comment"]])
data = "\ufeff" + buf.getvalue() # BOM 便于 Excel 识别 UTF-8
return StreamingResponse(
iter([data.encode("utf-8")]),
media_type="text/csv; charset=utf-8",
headers={"Content-Disposition": f"attachment; filename=incubator_reports_{month or 'all'}.csv"},
)
@router.post("/reports", summary="新建/保存草稿(提交方)")
async def incubator_create_report(
body: ReportCreateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.create_report(db, ident, body.model_dump())
except (LookupError, PermissionError) as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/reports/{report_id}", summary="报告详情")
async def incubator_report_detail(
report_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.get_report(db, ident, report_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.put("/reports/{report_id}", summary="更新报告(draft/已提交可撤回后改)")
async def incubator_update_report(
report_id: str, body: ReportUpdateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
data = body.model_dump()
data["_force_reopen"] = body._force_reopen
try:
return await service.update_report(db, ident, report_id, data)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reports/{report_id}/submit", summary="提交审核 draft→submitted")
async def incubator_submit_report(
report_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.submit_report(db, ident, report_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reports/{report_id}/reopen", summary="撤回 submitted→draft")
async def incubator_reopen_report(
report_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.reopen_report(db, ident, report_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reports/{report_id}/review", summary="审核 approve/reject(管理方)")
async def incubator_review_report(
report_id: str, body: ReviewReportRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.review_report(db, ident, report_id,
action=body.action, comment=body.comment)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
# ---------------------------------------------------------------------------
# 共享区域资源
# ---------------------------------------------------------------------------
@router.get("/areas", summary="共享区域列表(直播间/会议室)")
async def incubator_areas(
area_type: str = "", only_enabled: bool = True,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.list_areas(db, ident, area_type=area_type,
only_enabled=only_enabled)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.get("/areas/{area_id}", summary="共享区域详情")
async def incubator_area_detail(
area_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.get_area(db, ident, area_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.post("/areas", summary="新建共享区域(管理方)")
async def incubator_create_area(
body: AreaCreateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.create_area(db, ident, body.model_dump())
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.put("/areas/{area_id}", summary="编辑共享区域(管理方)")
async def incubator_update_area(
area_id: str, body: AreaUpdateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.update_area(db, ident, area_id, body.model_dump())
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.delete("/areas/{area_id}", summary="删除共享区域(管理方)")
async def incubator_delete_area(
area_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
ok = await service.delete_area(db, ident, area_id)
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
if not ok:
raise HTTPException(status_code=404, detail="共享区域不存在")
return {"ok": True}
# ---------------------------------------------------------------------------
# 共享区域使用申请
# ---------------------------------------------------------------------------
@router.get("/reservations", summary="申请列表(管理方=全园区,提交方=本企业)")
async def incubator_reservations(
date: str = "", status: str = "", area_id: str = "",
page: int = 1, page_size: int = 50,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.list_reservations(db, ident, date=date, status=status,
area_id=area_id, page=page, page_size=page_size)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.post("/reservations", summary="发起共享区域使用申请(冲突检测)")
async def incubator_create_reservation(
body: ReservationCreateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.create_reservation(db, ident, body.model_dump())
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reservations/{rsv_id}/review", summary="审批+备案(管理方)")
async def incubator_review_reservation(
rsv_id: str, body: ReviewReservationRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.review_reservation(
db, ident, rsv_id, action=body.action, comment=body.comment,
record_received=body.record_received,
record_safety_notified=body.record_safety_notified,
record_handler=body.record_handler)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reservations/{rsv_id}/cancel", summary="取消申请(发起人/管理方)")
async def incubator_cancel_reservation(
rsv_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.cancel_reservation(db, ident, rsv_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.post("/reservations/{rsv_id}/finish", summary="标记使用结束(管理方)")
async def incubator_finish_reservation(
rsv_id: str,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.finish_reservation(db, ident, rsv_id)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/settings", summary="园区设置(注意事项/开放说明/月报说明)")
async def incubator_get_settings(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager and not ident.company_id:
raise HTTPException(status_code=403, detail="当前账号不属于昆明市大学生创业园,无法使用本应用")
return await service.get_settings(db, ident)
@router.put("/settings", summary="更新园区设置(管理方)")
async def incubator_update_settings(
body: SettingsUpdateRequest,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.update_settings(db, ident, body.model_dump())
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/company", summary="提交方企业基本信息(表单自动识别填入)")
async def incubator_company_profile(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager and not ident.company_id:
raise HTTPException(status_code=403, detail="当前账号不属于昆明市大学生创业园,无法使用本应用")
return await service.get_company_profile(db, ident)
@router.get("/company/members", summary="企业绑定成员列表(联系人自动填入)")
async def incubator_company_members(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager and not ident.company_id:
raise HTTPException(status_code=403, detail="当前账号不属于昆明市大学生创业园,无法使用本应用")
return await service.list_company_members(db, ident)
# ---------------------------------------------------------------------------
# 数据大屏 / 企业列表 / 区域时段分布 / 汇总导出
# ---------------------------------------------------------------------------
@router.get("/companies", summary="在园企业列表(数据大屏下拉 / 报表筛选)")
async def incubator_companies(
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.list_companies(db, ident)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
@router.get("/stats", summary="数据大屏统计(本月/总计/单企业,tab+下拉控制)")
async def incubator_stats(
dim: str = "month", # month|total|company
month: str = "", # dim=month 时指定月份,默认本月
company_id: str = "", # dim=company 时指定企业
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.incubator_stats(db, ident, dim=dim, month=month,
company_id=company_id)
except LookupError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/stats/export", summary="导出汇总统计 CSV(管理方,同月报统计表格式)")
async def incubator_stats_export(
dim: str = "month",
month: str = "",
company_id: str = "",
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
if not ident.is_manager:
raise HTTPException(status_code=403, detail="仅管理方可导出汇总")
stats = await service.incubator_stats(db, ident, dim=dim, month=month,
company_id=company_id)
import io
import csv
buf = io.StringIO()
w = csv.writer(buf)
w.writerow(["昆明市大学生创业园 · 运营数据汇总", ""])
w.writerow(["统计维度", {"month": "本月", "total": "全部累计", "company": "单企业"}.get(dim, dim)])
w.writerow(["统计月份", stats.get("month") or "全部"])
w.writerow(["统计企业", stats.get("company_name") or "全园区"])
w.writerow(["生成时间", stats.get("generated_at", "")])
w.writerow([])
w.writerow(["—— 园区与报告 ——", ""])
w.writerow(["在园企业数", stats["companies"]["total"]])
w.writerow(["报告总数", stats["reports"]["total"]])
w.writerow(["已提交", stats["reports"]["submitted"]])
w.writerow(["已通过", stats["reports"]["approved"]])
w.writerow(["待审核", stats["reports"]["pending"]])
w.writerow(["提交率(%)", stats["reports"]["submit_rate"]])
w.writerow([])
w.writerow(["—— 经营指标合计(万元) ——", ""])
fin = stats["finance"]
w.writerow(["当月营业额", fin["month_revenue_wan"]])
w.writerow(["年平均营业额", fin["avg_year_revenue_wan"]])
w.writerow(["当月毛利润", fin["month_gross_profit_wan"]])
w.writerow(["当月缴税", fin["month_tax_wan"]])
w.writerow(["研发当月投入", fin["rd_invest_wan"]])
w.writerow(["创业担保贷款", fin["loan_startup_wan"]])
w.writerow(["云岭创业贷款", fin["loan_yunling_wan"]])
w.writerow(["创业大赛扶持", fin["contest_award_wan"]])
w.writerow(["获得专利(项)", fin["patents"]])
w.writerow(["带动就业(人)", fin["jobs_created"]])
w.writerow([])
w.writerow(["—— 共享区域使用 ——", ""])
rsv = stats["reservations"]
w.writerow(["申请总数", rsv["total"]])
w.writerow(["待审批", rsv["pending"]])
w.writerow(["已通过", rsv["approved"]])
w.writerow(["已拒绝", rsv["rejected"]])
w.writerow(["已取消", rsv["cancelled"]])
w.writerow(["已结束", rsv["finished"]])
w.writerow(["使用率(%)", rsv["usage_rate"]])
w.writerow([])
w.writerow(["—— 共享区域资源 ——", ""])
ar = stats["areas"]
w.writerow(["区域总数", ar["total"]])
w.writerow(["开放中", ar["enabled"]])
w.writerow(["维护中", ar["maintenance"]])
w.writerow(["已封闭", ar["closed"]])
w.writerow([])
w.writerow(["—— 月度趋势(近 12 月) ——", ""])
w.writerow(["月份", "提交报告数", "当月营业额(万)", "带动就业(人)"])
for t in stats.get("trend", []):
w.writerow([t["month"], t["reports"], t["revenue"], t["jobs"]])
data = "\ufeff" + buf.getvalue()
return StreamingResponse(
iter([data.encode("utf-8")]),
media_type="text/csv; charset=utf-8",
headers={"Content-Disposition": f"attachment; filename=kmu_stats_{dim}_{month or 'all'}.csv"},
)
@router.get("/areas/{area_id}/schedule", summary="共享区域时段分布(表格:日期×时段占用)")
async def incubator_area_schedule(
area_id: str, days: int = 7,
db: Database = Depends(get_db),
user: dict = Depends(get_current_user),
):
ident = await resolve_identity(db, user)
try:
return await service.area_schedule(db, ident, area_id, days=days)
except LookupError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc