# _*_ coding : UTF-8 _*_ # @Time : 2025/03/24 02:29:03 # @UpdateTime : 2025/03/24 02:29:03 # @Author : sonder # @File : version.py # @Comment : 本程序用于生成版本信息增删改查接口 import json import uuid from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, Path, Request, Query from fastapi.responses import JSONResponse from annotation.auth import Auth from annotation.log import Log from config.constant import BusinessType from controller.login import LoginController from models import Version, HtsClass, HtsItem, File from schemas.common import BaseResponse, DeleteListParams from schemas.hts import AddHTSClassParams, UpdateHTSClassParams, GetHTSClassInfoResponse, GetHTSClassListResponse, \ ImportHtsItemParams from schemas.hts import AddHtsItemParams, UpdateHtsItemParams, GetHtsItemInfoResponse, GetHtsItemListResponse from schemas.hts import AddVersionParams, UpdateVersionParams, GetVersionInfoResponse, GetVersionListResponse from utils.response import Response htsAPI = APIRouter( prefix="/hts", dependencies=[Depends(LoginController.get_current_user)], ) @htsAPI.post("/version/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增税率编码版本") @Log(title="新增税率编码版本", business_type=BusinessType.INSERT) @Auth(permission_list=["version:btn:add"]) async def add_version(request: Request, params: AddVersionParams): if await Version.get_or_none( version=params.version, date=params.date, url=params.url, del_flag=1 ): return Response.error(msg="税率编码版本已存在!") version = await Version.create( version=params.version, date=params.date, url=params.url, ) if version: return Response.success(msg="新增成功!") else: return Response.error(msg="新增失败") @htsAPI.delete("/version/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除税率编码版本") @htsAPI.post("/version/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除税率编码版本") @Log(title="删除税率编码版本", business_type=BusinessType.DELETE) @Auth(permission_list=["version:btn:delete"]) async def delete_version(request: Request, id: str = Path(description="税率编码版本ID")): if version := await Version.get_or_none(id=id, del_flag=1): version.del_flag = 0 await version.save() return Response.success(msg="删除成功") else: return Response.error(msg="税率编码版本不存在!") @htsAPI.delete("/version/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除税率编码版本") @htsAPI.post("/version/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除税率编码版本") @Log(title="批量删除税率编码版本", business_type=BusinessType.DELETE) @Auth(permission_list=["version:btn:delete"]) async def delete_version_list(request: Request, params: DeleteListParams): for id in set(params.ids): if version := await Version.get_or_none(id=id, del_flag=1): version.del_flag = 0 await version.save() return Response.success(msg="删除成功") @htsAPI.put("/version/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改税率编码版本") @htsAPI.post("/version/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改税率编码版本") @Log(title="修改税率编码版本", business_type=BusinessType.UPDATE) @Auth(permission_list=["version:btn:update"]) async def update_version(request: Request, params: UpdateVersionParams, id: str = Path(description="税率编码版本ID")): if version := await Version.get_or_none(id=id, del_flag=1): print(params) version.version = params.version version.date = params.date version.url = params.url await version.save() return Response.success(msg="修改成功") else: return Response.error(msg="税率编码版本不存在") @htsAPI.get("/version/info/{id}", response_class=JSONResponse, response_model=GetVersionInfoResponse, summary="获取税率编码版本信息") @Log(title="获取税率编码版本信息", business_type=BusinessType.SELECT) @Auth(permission_list=["version:btn:info"]) async def get_version_info(request: Request, id: str = Path(description="税率编码版本ID")): if version := await Version.get_or_none(id=id, del_flag=1): data = { "id": version.id, "create_time": version.create_time, "update_time": version.update_time, "version": version.version, "date": version.date, "url": version.url, } return Response.success(data=data) else: return Response.error(msg="税率编码版本不存在") @htsAPI.get("/version/list", response_class=JSONResponse, response_model=GetVersionListResponse, summary="获取税率编码版本列表") @Log(title="获取税率编码版本列表", business_type=BusinessType.SELECT) @Auth(permission_list=["version:btn:list"]) async def get_version_list( request: Request, page: int = Query(default=1, description="当前页码"), pageSize: int = Query(default=10, description="每页数量"), version: Optional[str] = Query(default=None, description="版本号"), date: Optional[str] = Query(default=None, description="版本日期"), url: Optional[str] = Query(default=None, description="下载地址"), ): filterArgs = { "version__icontains": version, "date__icontains": date, "url__icontains": url, } filterArgs = {k: v for k, v in filterArgs.items() if v is not None} total = await Version.filter(**filterArgs, del_flag=1).count() data = await Version.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values( id="id", create_time="create_time", update_time="update_time", version="version", date="date", url="url", ) return Response.success(data={ "total": total, "result": data, "page": page, "pageSize": pageSize, }) @htsAPI.post("/class/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增编码类别") @Log(title="新增编码类别", business_type=BusinessType.INSERT) @Auth(permission_list=["htsclass:btn:add"]) async def add_htsclass(request: Request, params: AddHTSClassParams): if await HtsClass.get_or_none( class_name=params.class_name, class_description=params.class_description, chapter_name=params.chapter_name, chapter_description=params.chapter_description, del_flag=1 ): return Response.error(msg="编码类别已存在!") htsclass = await HtsClass.create( class_name=params.class_name, class_description=params.class_description, chapter_name=params.chapter_name, chapter_description=params.chapter_description, ) if htsclass: return Response.success(msg="新增成功!") else: return Response.error(msg="新增失败") @htsAPI.delete("/class/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码类别") @htsAPI.post("/class/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码类别") @Log(title="删除编码类别", business_type=BusinessType.DELETE) @Auth(permission_list=["htsclass:btn:delete"]) async def delete_htsclass(request: Request, id: str = Path(description="编码类别ID")): if htsclass := await HtsClass.get_or_none(id=id, del_flag=1): htsclass.del_flag = 0 await htsclass.save() return Response.success(msg="删除成功") else: return Response.error(msg="编码类别不存在!") @htsAPI.delete("/class/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码类别") @htsAPI.post("/class/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码类别") @Log(title="批量删除编码类别", business_type=BusinessType.DELETE) @Auth(permission_list=["htsclass:btn:delete"]) async def delete_htsclass_list(request: Request, params: DeleteListParams): for id in set(params.ids): if htsclass := await HtsClass.get_or_none(id=id, del_flag=1): htsclass.del_flag = 0 await htsclass.save() return Response.success(msg="删除成功") @htsAPI.put("/class/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改编码类别") @htsAPI.post("/class/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改编码类别") @Log(title="修改编码类别", business_type=BusinessType.UPDATE) @Auth(permission_list=["htsclass:btn:update"]) async def update_htsclass(request: Request, params: UpdateHTSClassParams, id: str = Path(description="编码类别ID")): if htsclass := await HtsClass.get_or_none(id=id, del_flag=1): htsclass.class_name = params.class_name htsclass.class_description = params.class_description htsclass.chapter_name = params.chapter_name htsclass.chapter_description = params.chapter_description await htsclass.save() return Response.success(msg="修改成功") else: return Response.error(msg="编码类别不存在") @htsAPI.get("/class/info/{id}", response_class=JSONResponse, response_model=GetHTSClassInfoResponse, summary="获取编码类别信息") @Log(title="获取编码类别信息", business_type=BusinessType.SELECT) @Auth(permission_list=["htsclass:btn:info"]) async def get_htsclass_info(request: Request, id: str = Path(description="编码类别ID")): if htsclass := await HtsClass.get_or_none(id=id, del_flag=1): data = { "id": htsclass.id, "create_time": htsclass.create_time, "update_time": htsclass.update_time, "class_name": htsclass.class_name, "class_description": htsclass.class_description, "chapter_name": htsclass.chapter_name, "chapter_description": htsclass.chapter_description, } return Response.success(data=data) else: return Response.error(msg="编码类别不存在") @htsAPI.get("/class/list", response_class=JSONResponse, response_model=GetHTSClassListResponse, summary="获取编码类别列表") @Log(title="获取编码类别列表", business_type=BusinessType.SELECT) @Auth(permission_list=["htsclass:btn:list"]) async def get_htsclass_list( request: Request, page: int = Query(default=1, description="当前页码"), pageSize: int = Query(default=10, description="每页数量"), class_name: Optional[str] = Query(default=None, description="类名"), class_description: Optional[str] = Query(default=None, description="类描述"), chapter_name: Optional[str] = Query(default=None, description="章节"), chapter_description: Optional[str] = Query(default=None, description="章节描述"), ): filterArgs = { "class_name__icontains": class_name, "class_description__icontains": class_description, "chapter_name__icontains": chapter_name, "chapter_description__icontains": chapter_description, } filterArgs = {k: v for k, v in filterArgs.items() if v is not None} total = await HtsClass.filter(**filterArgs, del_flag=1).count() data = await HtsClass.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values( id="id", create_time="create_time", update_time="update_time", class_name="class_name", class_description="class_description", chapter_name="chapter_name", chapter_description="chapter_description", ) return Response.success(data={ "total": total, "result": data, "page": page, "pageSize": pageSize, }) @htsAPI.post("/item/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增编码项") @Log(title="新增编码项", business_type=BusinessType.INSERT) @Auth(permission_list=["htsitem:btn:add"]) async def add_htsitem(request: Request, params: AddHtsItemParams): if await HtsItem.get_or_none( parent_id=params.parent_id, htsno=params.htsno, indent=params.indent, description=params.description, units=params.units, general=params.general, special=params.special, other=params.other, quota_quantity=params.quota_quantity, additional_duties=params.additional_duties, footnotes=params.footnotes, class_id=params.class_id, version_id=params.version_id, del_flag=1 ): return Response.error(msg="编码项目已存在!") htsitem = await HtsItem.create( parent_id=params.parent_id, htsno=params.htsno, indent=params.indent, description=params.description, units=params.units, general=params.general, special=params.special, other=params.other, quota_quantity=params.quota_quantity, additional_duties=params.additional_duties, footnotes=params.footnotes, class_id=params.class_id, version_id=params.version_id, ) if htsitem: return Response.success(msg="新增成功!") else: return Response.error(msg="新增失败") @htsAPI.delete("/item/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码项") @htsAPI.post("/item/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码项") @Log(title="删除编码项", business_type=BusinessType.DELETE) @Auth(permission_list=["htsitem:btn:delete"]) async def delete_htsitem(request: Request, id: str = Path(description="编码项目ID")): if htsitem := await HtsItem.get_or_none(id=id, del_flag=1): htsitem.del_flag = 0 await htsitem.save() return Response.success(msg="删除成功") else: return Response.error(msg="编码项目不存在!") @htsAPI.delete("/item/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码项") @htsAPI.post("/item/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码项") @Log(title="批量删除编码项", business_type=BusinessType.DELETE) @Auth(permission_list=["htsitem:btn:delete"]) async def delete_htsitem_list(request: Request, params: DeleteListParams): for id in set(params.ids): if htsitem := await HtsItem.get_or_none(id=id, del_flag=1): htsitem.del_flag = 0 await htsitem.save() return Response.success(msg="删除成功") @htsAPI.put("/item/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改编码项") @htsAPI.post("/item/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改编码项") @Log(title="修改编码项", business_type=BusinessType.UPDATE) @Auth(permission_list=["htsitem:btn:update"]) async def update_htsitem(request: Request, params: UpdateHtsItemParams, id: str = Path(description="编码项目ID")): if htsitem := await HtsItem.get_or_none(id=id, del_flag=1): htsitem.parent_id = params.parent_id htsitem.htsno = params.htsno htsitem.indent = params.indent htsitem.description = params.description htsitem.units = params.units htsitem.general = params.general htsitem.special = params.special htsitem.other = params.other htsitem.quota_quantity = params.quota_quantity htsitem.additional_duties = params.additional_duties htsitem.footnotes = params.footnotes if class_ := await HtsClass.get_or_none(id=params.class_id, del_flag=1): htsitem.class_ = class_ if version := await Version.get_or_none(id=params.version_id, del_flag=1): htsitem.version = version htsitem.version_id = params.version_id await htsitem.save() return Response.success(msg="修改成功") else: return Response.error(msg="编码项目不存在") @htsAPI.get("/item/info/{id}", response_class=JSONResponse, response_model=GetHtsItemInfoResponse, summary="获取编码项信息") @Log(title="获取编码项信息", business_type=BusinessType.SELECT) @Auth(permission_list=["htsitem:btn:info"]) async def get_htsitem_info(request: Request, id: str = Path(description="编码项目ID")): if htsitem := await HtsItem.get_or_none(id=id, del_flag=1): data = { "id": htsitem.id, "create_time": htsitem.create_time, "update_time": htsitem.update_time, "parent_id": htsitem.parent_id, "htsno": htsitem.htsno, "indent": htsitem.indent, "description": htsitem.description, "units": htsitem.units, "general": htsitem.general, "special": htsitem.special, "other": htsitem.other, "quota_quantity": htsitem.quota_quantity, "additional_duties": htsitem.additional_duties, "footnotes": htsitem.footnotes, "class_id": htsitem.class_id, "version_id": htsitem.version_id, } return Response.success(data=data) else: return Response.error(msg="编码项目不存在") @htsAPI.get("/item/list", response_class=JSONResponse, response_model=GetHtsItemListResponse, summary="获取编码项列表") @Log(title="获取编码项列表", business_type=BusinessType.SELECT) @Auth(permission_list=["htsitem:btn:list"]) async def get_htsitem_list( request: Request, page: int = Query(default=1, description="当前页码"), pageSize: int = Query(default=10, description="每页数量"), htsno: Optional[str] = Query(default=None, description="编码"), description: Optional[str] = Query(default=None, description="描述"), units: Optional[str] = Query(default=None, description="单位列表"), general: Optional[str] = Query(default=None, description="通用税率"), special: Optional[str] = Query(default=None, description="特殊税率,适用于特定国家或地区"), other: Optional[str] = Query(default=None, description="其他税率"), quota_quantity: Optional[str] = Query(default=None, description="配额数量"), additional_duties: Optional[str] = Query(default=None, description="附加税"), footnotes: Optional[str] = Query(default=None, description="脚注列表"), class_id: Optional[str] = Query(default=None, description="所属类"), version_id: Optional[str] = Query(default=None, description="所属版本"), ): filterArgs = { "htsno__icontains": htsno, "description__icontains": description, "units__icontains": units, "general__icontains": general, "special__icontains": special, "other__icontains": other, "quota_quantity__icontains": quota_quantity, "additional_duties__icontains": additional_duties, "footnotes__icontains": footnotes, "class__id": class_id, "version_id": version_id, } filterArgs = {k: v for k, v in filterArgs.items() if v is not None} total = await HtsItem.filter(**filterArgs, del_flag=1).count() data = await HtsItem.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values( id="id", create_time="create_time", update_time="update_time", parent_id="parent_id", htsno="htsno", indent="indent", description="description", units="units", general="general", special="special", other="other", quota_quantity="quota_quantity", additional_duties="additional_duties", footnotes="footnotes", class_id="class__id", version_id="version_id", ) return Response.success(data={ "total": total, "result": data, "page": page, "pageSize": pageSize, }) @htsAPI.post("/item/import", response_class=JSONResponse, response_model=BaseResponse, summary="导入编码项") @Log(title="导入编码项", business_type=BusinessType.INSERT) @Auth(permission_list=["htsitem:btn:import"]) async def add_htsitem(request: Request, params: ImportHtsItemParams): version = await Version.get_or_none(id=params.version_id, del_flag=1) if not version: return Response.error(msg="版本不存在") class_ = await HtsClass.get_or_none(id=params.class_id, del_flag=1) if not class_: return Response.error(msg="编码类不存在") file = await File.get_or_none(id=params.file_id, del_flag=1) if not file: return Response.error(msg="文件不存在") if await HtsItem.get_or_none(class_=params.class_id, version=params.version_id): return Response.error(msg="编码项已存在") def build_hierarchy_with_ids(data): hierarchy = [] stack = [] for item in data: current_level = int(item['indent']) current_item = { 'id': str(uuid.uuid4()), # 生成唯一的 UUID 'indent': item['indent'], 'htsno': item['htsno'].replace(".", "").strip(), 'description': item['description'], 'parent_id': None, # 默认没有父级, "units": json.dumps(item["units"], ensure_ascii=False), "general": item["general"], "special": item["special"], "other": item["other"], "footnotes": json.dumps(item["footnotes"], ensure_ascii=False), "quota_quantity": item["quotaQuantity"], "additional_duties": item["additionalDuties"], "addiitional_duties": item["addiitionalDuties"] } # 找到当前项的父级 while stack and int(stack[-1]['indent']) >= current_level: stack.pop() if stack: # 设置当前项的 parent_id 为父级的 id current_item['parent_id'] = stack[-1]['item']['id'] # 将当前项添加到层级结构中 hierarchy.append(current_item) # 将当前项压入栈中 stack.append({'indent': current_level, 'item': current_item}) return hierarchy with open(file.absolute_path, 'r', encoding='utf-8') as r: data = json.load(r) for x in data: x["indent"] = str(int(x["indent"]) + 1) data.append({ "htsno": str(class_.chapter_name).replace("Chapter", "").strip() if int( str(class_.chapter_name).replace("Chapter", "").strip(" ")) > 10 else "0" + str(class_.chapter_name).replace( "Chapter", "").strip(), "indent": "0", "description": class_.class_description, "units": [], "general": "", "special": "", "other": "", "footnotes": [], "quotaQuantity": "", "additionalDuties": "", "addiitionalDuties": "" }) hierarchy = build_hierarchy_with_ids(data) # 批量插入查询结果 create_tasks = [ HtsItem( id=item["id"], parent_id=item["parent_id"], htsno=item["htsno"], indent=item["indent"], description=item["description"], units=item["units"], general=item["general"], special=item["special"], other=item["other"], quota_quantity=item["quota_quantity"], additional_duties=item["additional_duties"], footnotes=item["footnotes"], class_=class_, version=version ) for item in hierarchy ] await HtsItem.bulk_create(create_tasks) return Response.success()