初始化项目
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
待办工单明细推送。
|
||||
|
||||
对应文档接口:5、推送工单详情
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from sqlalchemy import select, desc
|
||||
from tornado.httpclient import HTTPResponse, HTTPRequest
|
||||
|
||||
import dock
|
||||
import models
|
||||
from dock.oa import oa_api_request
|
||||
from models.govs_order_master import GovsOrderMaster
|
||||
from models.govs_order_detail import GovsOrderDetail
|
||||
from models.govs_order_user import GovsOrderUser
|
||||
from models.govs_push_status import GovsPushStatus
|
||||
from paste.core.logging import echo_log
|
||||
from paste.util import udict
|
||||
from paste.web import requests
|
||||
|
||||
GovsOrderDetailMapping = {
|
||||
GovsOrderMaster.id.key: 'gdId',
|
||||
GovsOrderDetail.order_id.key: 'workOrderNo',
|
||||
GovsOrderUser.customer_name.key: 'name',
|
||||
GovsOrderUser.customer_sex.key: 'gender',
|
||||
GovsOrderUser.customer_credentials_type.key: 'documentType',
|
||||
GovsOrderUser.customer_credentials_no.key: 'idNumber',
|
||||
GovsOrderDetail.call_number.key: 'incomingCallNumber',
|
||||
GovsOrderDetail.call_time.key: 'callTime',
|
||||
GovsOrderDetail.order_source_for_view.key: 'workOrderStatus',
|
||||
GovsOrderUser.customer_connect_phone.key: 'contactPhoneNumber',
|
||||
GovsOrderDetail.belong_platform_name.key: 'acceptancePlatform',
|
||||
GovsOrderDetail.form_type.key: 'formType',
|
||||
GovsOrderDetail.case_is_visit.key: 'whetherToFollowUp',
|
||||
GovsOrderDetail.case_is_urgent.key: 'urgencyLevel',
|
||||
GovsOrderDetail.info_protect.key: 'informationProtection',
|
||||
GovsOrderDetail.relate_order_count.key: 'relatedWorkOrderNo',
|
||||
GovsOrderDetail.service_object_type.key: 'serviceObjectType',
|
||||
}
|
||||
"""
|
||||
数据推送映射关系。
|
||||
"""
|
||||
|
||||
|
||||
async def after_push_order_detail_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
|
||||
"""
|
||||
工单推送请求响应后的处理程序。
|
||||
|
||||
:param response: 响应对象
|
||||
:param retry_queue: 重试队列
|
||||
"""
|
||||
body = response.body.decode()
|
||||
echo_log(body)
|
||||
body_data = json.loads(body)
|
||||
code = udict.get_by_path(body_data, 'code')
|
||||
message = udict.get_by_path(body_data, 'msg')
|
||||
if code == 200:
|
||||
govs_task_id = getattr(response.request, "govs_task_id")
|
||||
await GovsPushStatus.set_push_order_detail_status(govs_task_id)
|
||||
echo_log(f"推送工单详情成功.")
|
||||
else:
|
||||
echo_log(f"推送工单详情失败:{message}")
|
||||
|
||||
if retry_queue:
|
||||
echo_log(f"工单详情重试队列中有:{retry_queue.qsize()} 个请求在等待.")
|
||||
|
||||
|
||||
async def done_push_order_detail(response_list: list[HTTPResponse]):
|
||||
"""
|
||||
推送完成工单详情后的回调
|
||||
"""
|
||||
unique_task_ids = set()
|
||||
for response in response_list:
|
||||
task_id = getattr(response.request, 'govs_task_id', None)
|
||||
if task_id:
|
||||
unique_task_ids.add(task_id)
|
||||
return unique_task_ids
|
||||
|
||||
|
||||
async def push_order_detail(fetch_size: int = 50,
|
||||
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
|
||||
"""
|
||||
推送12345工单详情。
|
||||
|
||||
:param fetch_size: 本次推送数量
|
||||
:param task_id: 待办任务 ID 可选
|
||||
"""
|
||||
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
|
||||
task_query = select(GovsOrderMaster.id).order_by(desc(GovsOrderMaster.id))
|
||||
if task_id is not None:
|
||||
if isinstance(task_id, list):
|
||||
task_query = task_query.where(GovsOrderMaster.id.in_(task_id))
|
||||
echo_log(f"本次推送待办列表:{task_id} 的详细数据...")
|
||||
else:
|
||||
task_query = task_query.where(GovsOrderMaster.id == task_id)
|
||||
echo_log(f"本次推送待办:{task_id} 的详细数据...")
|
||||
else:
|
||||
task_query = task_query.limit(fetch_size)
|
||||
echo_log(f"本次推送前 {fetch_size} 条待办的详细数据...")
|
||||
task_id_list = (await GovsOrderMaster.orm_execute_scalars(task_query)).all()
|
||||
task_id_list = [f"{id}" for id in task_id_list]
|
||||
|
||||
# 查询属于这些任务的所有详细数据
|
||||
detail_query = select(
|
||||
GovsOrderMaster.id, GovsOrderMaster.order_id, GovsOrderUser.customer_name, GovsOrderUser.customer_sex,
|
||||
GovsOrderDetail.call_number, GovsOrderUser.customer_connect_phone, GovsOrderDetail.belong_platform_name,
|
||||
GovsOrderDetail.area_code_area, GovsOrderDetail.area_code_city, GovsOrderDetail.area_code_street,
|
||||
GovsOrderDetail.address_detail, GovsOrderDetail.form_type, GovsOrderDetail.case_accord_type_one_name,
|
||||
GovsOrderDetail.case_accord_type_two_name, GovsOrderDetail.case_accord_type_three_name,
|
||||
GovsOrderDetail.case_is_visit, GovsOrderDetail.order_source_for_view,
|
||||
GovsOrderDetail.order_source, GovsOrderDetail.order_source_detail, GovsOrderDetail.case_is_urgent,
|
||||
GovsOrderDetail.info_protect, GovsOrderDetail.relate_order_count, GovsOrderDetail.service_object_type,
|
||||
GovsOrderUser.customer_credentials_type, GovsOrderUser.customer_credentials_no,
|
||||
GovsOrderDetail.call_time
|
||||
).join(
|
||||
GovsOrderUser, GovsOrderMaster.id == GovsOrderUser.master_id
|
||||
).join(
|
||||
GovsOrderDetail, GovsOrderMaster.id == GovsOrderDetail.master_id
|
||||
).where(
|
||||
GovsOrderMaster.id.in_(task_id_list)
|
||||
)
|
||||
|
||||
govs_task_df = await GovsOrderMaster.query_as_df(detail_query)
|
||||
# 格式化为字符串
|
||||
govs_task_df[GovsOrderMaster.id.key] = govs_task_df[GovsOrderMaster.id.key].astype(str)
|
||||
govs_task_df[GovsOrderDetail.relate_order_count.key] = govs_task_df[GovsOrderDetail.relate_order_count.key].astype(
|
||||
str)
|
||||
# 拼接诉求地址
|
||||
govs_task_df['appealAddress'] = (govs_task_df[GovsOrderDetail.area_code_city.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.area_code_area.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.area_code_street.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.address_detail.key])
|
||||
# 拼接诉求归口
|
||||
govs_task_df['appealCategory'] = (govs_task_df[GovsOrderDetail.case_accord_type_one_name.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.case_accord_type_two_name.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.case_accord_type_three_name.key])
|
||||
# 拼接诉求来源
|
||||
govs_task_df['appealSource'] = (govs_task_df[GovsOrderDetail.order_source.key] + '/' +
|
||||
govs_task_df[GovsOrderDetail.order_source_detail.key])
|
||||
# 日期转换为字符串
|
||||
govs_task_df[GovsOrderDetail.call_time.key] = govs_task_df[GovsOrderDetail.call_time.key].apply(
|
||||
lambda x: x.strftime('%Y-%m-%d %H:%M:%S') if pd.notna(x) and hasattr(x, 'strftime') else x
|
||||
)
|
||||
|
||||
# 处理无待办工单详情状态
|
||||
empty_task_ids = set(task_id_list) - set(govs_task_df[GovsOrderMaster.id.key].unique().tolist())
|
||||
empty_task_data = [
|
||||
{
|
||||
GovsPushStatus.master_id.key: govs_task_id,
|
||||
GovsPushStatus.push_order_status.key: 1
|
||||
}
|
||||
for govs_task_id in list(empty_task_ids)
|
||||
]
|
||||
empty_task_df = pd.DataFrame(empty_task_data)
|
||||
await GovsPushStatus.save_batch(empty_task_df)
|
||||
|
||||
# 处理数据映射,适应接口推送
|
||||
mapped_df = govs_task_df.rename(columns=GovsOrderDetailMapping)
|
||||
# 仅保留需要的列
|
||||
mapped_df = mapped_df[
|
||||
list(GovsOrderDetailMapping.values()) + ['appealAddress', 'appealCategory', 'appealSource']]
|
||||
# 这里把空数据都换成 None,以便存入数据库时是 null
|
||||
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
|
||||
|
||||
echo_log(f"正在准备请求队列...")
|
||||
# 构建请求队列
|
||||
govs_push_queue = asyncio.Queue()
|
||||
|
||||
# 向队列中填充请求对象
|
||||
for _h, row in mapped_df.iterrows():
|
||||
push_request = await oa_api_request.get_push_govs_order_detail_request(**row.to_dict())
|
||||
setattr(push_request, "govs_task_id", row.get('gdId'))
|
||||
await govs_push_queue.put(push_request)
|
||||
|
||||
# 并发提交推送请求
|
||||
echo_log(f"开始推送工单详情数据...")
|
||||
pushed_task_ids = await requests.async_concurrency(
|
||||
govs_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
|
||||
after_request=after_push_order_detail_request, after_done=done_push_order_detail
|
||||
)
|
||||
echo_log(f"工单详情推送已经完成...")
|
||||
return pushed_task_ids
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from paste.core import aio_pool
|
||||
|
||||
_runner = aio_pool.get_aio_runner()
|
||||
_runner(push_order_detail(fetch_size=60))
|
||||
@@ -0,0 +1,177 @@
|
||||
"""
|
||||
待签收工单推送。
|
||||
|
||||
对应文档接口:2、推送待签收工单列表
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import pandas as pd
|
||||
from sqlalchemy import select
|
||||
from tornado.httpclient import HTTPResponse, HTTPRequest
|
||||
|
||||
import models
|
||||
import apps
|
||||
import dock
|
||||
from dock.oa import oa_api_request
|
||||
from dock.govs import govs_save_sign
|
||||
from dock.oa_govs import oa_sign_task
|
||||
from models.govs_order_master import GovsOrderMaster
|
||||
from models.govs_push_status import GovsPushStatus
|
||||
from typing import Optional, Union
|
||||
from paste.core.logging import echo_log
|
||||
from paste.web import requests
|
||||
from paste.util import udict
|
||||
|
||||
GOVS_MASTER_MAPPING = {
|
||||
GovsOrderMaster.id.key: 'gdId',
|
||||
GovsOrderMaster.order_id.key: 'workOrderNo',
|
||||
GovsOrderMaster.case_content.key: 'appealContent',
|
||||
GovsOrderMaster.case_goal.key: 'appealPurpose',
|
||||
GovsOrderMaster.plan_sign_time.key: 'plannedSignOffTime',
|
||||
GovsOrderMaster.plan_finish_time.key: 'plannedCompletionTime',
|
||||
GovsOrderMaster.order_status.key: 'workOrderStatus',
|
||||
GovsOrderMaster.claim_status.key: 'signOffStatus',
|
||||
GovsOrderMaster.plan_back_time.key: 'returnDeadline',
|
||||
GovsOrderMaster.handle_time.key: 'assignToSubordinateTime',
|
||||
GovsOrderMaster.back_time.key: 'subordinateReturnTime',
|
||||
GovsOrderMaster.complete_time.key: 'subordinateCompletionTime',
|
||||
GovsOrderMaster.update_date.key: 'platformUpdateTime',
|
||||
GovsOrderMaster.service_object_type.key: 'appealType'
|
||||
}
|
||||
"""
|
||||
数据推送映射关系。
|
||||
"""
|
||||
|
||||
|
||||
async def after_push_order_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
|
||||
"""
|
||||
工单推送请求响应后的处理程序。
|
||||
|
||||
:param response: 响应对象
|
||||
:param retry_queue: 重试队列
|
||||
"""
|
||||
body = response.body.decode()
|
||||
echo_log(body)
|
||||
body_data = json.loads(body)
|
||||
code = udict.get_by_path(body_data, 'code')
|
||||
message = udict.get_by_path(body_data, 'msg')
|
||||
if code == 200:
|
||||
gov_task_id_list = getattr(response.request, "gov_task_id_list", [])
|
||||
order_push_data = [
|
||||
{
|
||||
GovsPushStatus.master_id.key: govs_task_id,
|
||||
GovsPushStatus.push_order_status.key: 1
|
||||
}
|
||||
for govs_task_id in gov_task_id_list
|
||||
]
|
||||
govs_task_push_df = pd.DataFrame(order_push_data)
|
||||
await GovsPushStatus.save_batch(govs_task_push_df)
|
||||
echo_log(f"推送待签收工单成功.")
|
||||
else:
|
||||
echo_log(f"推送待签收工单失败:{message}")
|
||||
|
||||
if retry_queue:
|
||||
echo_log(f"待签收工单重试队列中有:{retry_queue.qsize()} 个请求在等待.")
|
||||
|
||||
|
||||
async def done_order_push(response_list: list[HTTPResponse]):
|
||||
"""
|
||||
待签收工单列表推送完成的回调
|
||||
"""
|
||||
unique_task_ids = set()
|
||||
for response in response_list:
|
||||
gov_task_id_list = getattr(response.request, "gov_task_id_list", [])
|
||||
unique_task_ids.update(gov_task_id_list)
|
||||
return unique_task_ids
|
||||
|
||||
|
||||
async def push_order(fetch_size: int = 50, batch_size: int = 10,
|
||||
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
|
||||
"""
|
||||
推送待签收工单列表。
|
||||
|
||||
:param fetch_size: 本次推送数量
|
||||
:param batch_size: 分批时,每批大小
|
||||
:param task_id: 待办任务 ID 可选
|
||||
"""
|
||||
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
|
||||
task_query = select(GovsOrderMaster.id, GovsOrderMaster.order_id, GovsOrderMaster.case_content,
|
||||
GovsOrderMaster.case_goal, GovsOrderMaster.plan_finish_time, GovsOrderMaster.plan_sign_time,
|
||||
GovsOrderMaster.service_object_type, GovsOrderMaster.claim_status,
|
||||
GovsOrderMaster.plan_back_time,
|
||||
GovsOrderMaster.handle_time, GovsOrderMaster.back_time, GovsOrderMaster.complete_time,
|
||||
GovsOrderMaster.update_date, GovsOrderMaster.order_status).order_by(GovsOrderMaster.id)
|
||||
# 生产环境不推送已推送过的或已签收的
|
||||
if apps.get_active_env() == 'prod':
|
||||
task_query = task_query.join(
|
||||
GovsPushStatus, GovsPushStatus.master_id == GovsOrderMaster.id
|
||||
).where((GovsOrderMaster.govs_sign != 1) & (GovsPushStatus.push_order_status != 1))
|
||||
if task_id:
|
||||
if isinstance(task_id, list):
|
||||
task_query = task_query.where(GovsOrderMaster.id.in_(task_id))
|
||||
echo_log(f"本次推送待签收工单列表:{task_id} 的数据...")
|
||||
else:
|
||||
task_query = task_query.where(GovsOrderMaster.id == task_id)
|
||||
echo_log(f"本次推送待签收工单:{task_id} 的数据...")
|
||||
else:
|
||||
task_query = task_query.limit(fetch_size)
|
||||
echo_log(f"本次推送前 {fetch_size} 条待签收工单数据...")
|
||||
govs_task = await GovsOrderMaster.query_as_df(task_query)
|
||||
# 格式化为字符串
|
||||
govs_task[GovsOrderMaster.id.key] = govs_task[GovsOrderMaster.id.key].astype(str)
|
||||
for key in [GovsOrderMaster.plan_finish_time.key, GovsOrderMaster.plan_sign_time.key,
|
||||
GovsOrderMaster.handle_time.key, GovsOrderMaster.back_time.key,
|
||||
GovsOrderMaster.complete_time.key, GovsOrderMaster.update_date.key,
|
||||
GovsOrderMaster.plan_back_time.key]:
|
||||
govs_task[key] = govs_task[key].apply(
|
||||
lambda x: x.strftime('%Y-%m-%d %H:%M:%S') if pd.notna(x) and hasattr(x, 'strftime') else x
|
||||
)
|
||||
|
||||
# 处理数据映射,适应接口推送
|
||||
mapped_df = govs_task.rename(columns=GOVS_MASTER_MAPPING)
|
||||
# 这里把空数据都换成 None,以便存入数据库时是 null
|
||||
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
|
||||
|
||||
echo_log(f"正在准备请求队列...")
|
||||
# 构建请求队列
|
||||
govs_push_queue = asyncio.Queue()
|
||||
|
||||
# 向队列中填充请求对象
|
||||
for start in range(0, len(mapped_df), batch_size):
|
||||
batch_df: pd.DataFrame = mapped_df.iloc[start:start + batch_size]
|
||||
push_list = batch_df.to_dict('records')
|
||||
push_request = await oa_api_request.get_push_govs_order_master_request(push_list)
|
||||
setattr(push_request, "gov_task_id_list", batch_df['gdId'].unique().tolist())
|
||||
await govs_push_queue.put(push_request)
|
||||
|
||||
# 并发提交推送请求
|
||||
echo_log(f"开始推送待签收工单数据...")
|
||||
pushed_order_ids = await requests.async_concurrency(
|
||||
govs_push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
|
||||
after_request=after_push_order_request, after_done=done_order_push
|
||||
)
|
||||
echo_log(f"待签收数据推送已经完成...")
|
||||
return pushed_order_ids
|
||||
|
||||
|
||||
async def push_full_order(fetch_size: int = 50, batch_size: int = 10,
|
||||
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
|
||||
from dock.oa_govs import govs_push_process, govs_push_detail
|
||||
# 推送待办工单列表,并获取推送成功的工单id
|
||||
pushed_order_ids = await push_order(fetch_size, batch_size, task_id)
|
||||
pushed_order_ids = list(pushed_order_ids)
|
||||
# 只推送推送成功的工单的详情和办理过程
|
||||
await govs_push_detail.push_order_detail(task_id=pushed_order_ids)
|
||||
await govs_push_process.push_order_process(task_id=pushed_order_ids)
|
||||
# 在省12345平台签收推送成功的工单
|
||||
await govs_save_sign.sign_order_bypass_api(pushed_order_ids)
|
||||
# OA平台签收工单
|
||||
await oa_sign_task.sign_task(task_id=pushed_order_ids)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from paste.core import aio_pool
|
||||
|
||||
_runner = aio_pool.get_aio_runner()
|
||||
_runner(push_full_order(fetch_size=50))
|
||||
@@ -0,0 +1,260 @@
|
||||
"""
|
||||
待办工单办理过程推送。
|
||||
|
||||
对应文档接口:5、推送工单处理流程列表
|
||||
"""
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
from typing import Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from sqlalchemy import select, desc
|
||||
from tornado.httpclient import HTTPResponse, HTTPRequest
|
||||
|
||||
import dock
|
||||
import models
|
||||
from dock.oa import oa_api_request
|
||||
from dock.govs import govs_download_file
|
||||
from models.govs_order_master import GovsOrderMaster
|
||||
from models.govs_order_process import GovsOrderProcess
|
||||
from models.govs_push_status import GovsPushStatus
|
||||
from paste.core.logging import echo_log
|
||||
from paste.util import udict
|
||||
from paste.web import requests
|
||||
|
||||
GovsOrderProcessMapping = {
|
||||
GovsOrderProcess.id.key: 'id',
|
||||
GovsOrderProcess.master_id.key: 'parentId',
|
||||
GovsOrderProcess.action_name.key: 'processingSteps',
|
||||
GovsOrderProcess.handler_org_names.key: 'processingDepartment',
|
||||
GovsOrderProcess.handler_user_names.key: 'processor',
|
||||
GovsOrderProcess.deal_type.key: 'processingMethod',
|
||||
GovsOrderProcess.next_org_names.key: 'receivingDepartment',
|
||||
GovsOrderProcess.next_handler_user_names.key: 'receiver',
|
||||
GovsOrderProcess.adv_content.key: 'processingOpinion',
|
||||
GovsOrderProcess.deal_date.key: 'processingTime',
|
||||
GovsOrderProcess.plan_finish_time.key: 'plannedCompletionTime',
|
||||
GovsOrderProcess.remarks.key: 'remarks',
|
||||
GovsOrderProcess.attachment_dto_list.key: 'fileIdList'
|
||||
}
|
||||
"""
|
||||
数据推送映射关系。
|
||||
"""
|
||||
|
||||
|
||||
async def after_push_order_process_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
|
||||
"""
|
||||
工单推送请求响应后的处理程序。
|
||||
|
||||
:param response: 响应对象
|
||||
:param retry_queue: 重试队列
|
||||
"""
|
||||
body = response.body.decode()
|
||||
echo_log(body)
|
||||
body_data = json.loads(body)
|
||||
code = udict.get_by_path(body_data, 'code')
|
||||
message = udict.get_by_path(body_data, 'msg')
|
||||
if code == 200:
|
||||
govs_task_id = getattr(response.request, "govs_task_id")
|
||||
await GovsPushStatus.set_push_order_process_status(govs_task_id)
|
||||
echo_log(f"推送工单办理过程成功.")
|
||||
else:
|
||||
echo_log(f"推送工单办理过程失败:{message}")
|
||||
|
||||
if retry_queue:
|
||||
echo_log(f"工单办理过程重试队列中有:{retry_queue.qsize()} 个请求在等待.")
|
||||
|
||||
|
||||
async def done_push_order_process(response_list: list[HTTPResponse]):
|
||||
"""
|
||||
推送完成工单办理过程后的回调
|
||||
"""
|
||||
unique_task_ids = set()
|
||||
for response in response_list:
|
||||
task_id = getattr(response.request, 'govs_task_id', None)
|
||||
if task_id:
|
||||
unique_task_ids.add(task_id)
|
||||
return unique_task_ids
|
||||
|
||||
|
||||
async def done_attachment_download(response_list: list[HTTPResponse]):
|
||||
"""
|
||||
所有附件下载完成执行的处理程序。
|
||||
|
||||
:param response_list: 附件下载响应列表
|
||||
:return: 返回附件字典列表,每个元素包含文件名和io对象
|
||||
"""
|
||||
downloaded_attachments = []
|
||||
for response in response_list:
|
||||
file_name = getattr(response.request, "file_name", "file")
|
||||
file_io = io.BytesIO(response.body)
|
||||
downloaded_attachments.append({
|
||||
"file_name": file_name, "file_io": file_io
|
||||
})
|
||||
return downloaded_attachments
|
||||
|
||||
|
||||
async def done_attachment_upload(response_list: list[HTTPResponse]):
|
||||
"""
|
||||
所有附件上传到OA完成后执行的处理程序
|
||||
|
||||
:param response_list: 附件下载响应列表
|
||||
:return: 返回文件id列表
|
||||
"""
|
||||
file_ids = []
|
||||
for response in response_list:
|
||||
body = response.body.decode()
|
||||
echo_log(body)
|
||||
body_data = json.loads(body)
|
||||
nas = udict.get_by_path(body_data, 'n_a_s')
|
||||
if nas:
|
||||
oa_media_id = body_data.get('atts', [])[0].get('fileUrl')
|
||||
file_ids.append(oa_media_id)
|
||||
echo_log(f"省12345的办理过程的附件上传成功.")
|
||||
else:
|
||||
echo_log(f"省12345的办理过程的附件上传失败.")
|
||||
return file_ids
|
||||
|
||||
|
||||
async def download_and_upload_attachment(attachment_list: list):
|
||||
"""
|
||||
从省12345下载附件,并上传到OA
|
||||
|
||||
:param attachment_list: 附件信息列表
|
||||
:return: 返回上传OA成功的文件id列表
|
||||
"""
|
||||
download_queue = asyncio.Queue()
|
||||
for attachment in attachment_list:
|
||||
download_request = await govs_download_file.get_download_request('1773611023340371969', attachment['filePath'])
|
||||
setattr(download_request, 'file_name', attachment['attachName'])
|
||||
await download_queue.put(download_request)
|
||||
downloaded_attachments = await requests.async_concurrency(download_queue, con_count=dock.CONCURRENCY_COUNT,
|
||||
retry=dock.MAX_RETRY_COUNT,
|
||||
after_done=done_attachment_download)
|
||||
oa_upload_queue = asyncio.Queue()
|
||||
for downloaded_attachment in downloaded_attachments:
|
||||
upload_request = await oa_api_request.get_upload_request(downloaded_attachment['file_io'],
|
||||
downloaded_attachment['file_name'], False)
|
||||
await oa_upload_queue.put(upload_request)
|
||||
uploaded_attachment_ids = await requests.async_concurrency(oa_upload_queue, con_count=dock.CONCURRENCY_COUNT,
|
||||
retry=dock.MAX_RETRY_COUNT,
|
||||
after_done=done_attachment_upload)
|
||||
return uploaded_attachment_ids
|
||||
|
||||
|
||||
async def push_order_process(fetch_size: int = 50,
|
||||
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
|
||||
"""
|
||||
推送12345工单办理过程。
|
||||
|
||||
:param fetch_size: 本次推送数量
|
||||
:param task_id: 待办任务 ID 可选
|
||||
"""
|
||||
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
|
||||
task_query = select(GovsOrderMaster.id).order_by(desc(GovsOrderMaster.id))
|
||||
if task_id is not None:
|
||||
if isinstance(task_id, list):
|
||||
task_query = task_query.where(GovsOrderMaster.id.in_(task_id))
|
||||
echo_log(f"本次推送待办列表:{task_id} 的详细数据...")
|
||||
else:
|
||||
task_query = task_query.where(GovsOrderMaster.id == task_id)
|
||||
echo_log(f"本次推送待办:{task_id} 的详细数据...")
|
||||
else:
|
||||
task_query = task_query.limit(fetch_size)
|
||||
echo_log(f"本次推送前 {fetch_size} 条待办的详细数据...")
|
||||
govs_task_df = await GovsOrderProcess.query_as_df(task_query)
|
||||
|
||||
# 预处理数据方法
|
||||
def preprocess(df: pd.DataFrame):
|
||||
# 格式化为字符串
|
||||
df[GovsOrderProcess.id.key] = df[GovsOrderProcess.id.key].astype(str)
|
||||
df[GovsOrderProcess.master_id.key] = df[GovsOrderProcess.master_id.key].astype(
|
||||
str)
|
||||
|
||||
# 日期转换为字符串
|
||||
df[GovsOrderProcess.deal_date.key] = df[GovsOrderProcess.deal_date.key].apply(
|
||||
lambda x: x.strftime('%Y-%m-%d %H:%M:%S') if pd.notna(x) and hasattr(x, 'strftime') else ''
|
||||
)
|
||||
df[GovsOrderProcess.plan_finish_time.key] = df[GovsOrderProcess.plan_finish_time.key].apply(
|
||||
lambda x: x.strftime('%Y-%m-%d %H:%M:%S') if pd.notna(x) and hasattr(x, 'strftime') else ''
|
||||
)
|
||||
# 更名,并仅保留需要的列
|
||||
df = df.rename(columns=GovsOrderProcessMapping)
|
||||
df = df[list(GovsOrderProcessMapping.values())]
|
||||
df[GovsOrderProcess.master_id.key] = df['parentId']
|
||||
return df
|
||||
|
||||
# 填充处理过程
|
||||
await GovsOrderProcess.fill_process_info(govs_task_df, column_name='processLogBOList', preprocessing=preprocess)
|
||||
|
||||
# 处理无待办工单处理过程状态
|
||||
empty_govs_task_df = govs_task_df[govs_task_df['processLogBOList'].apply(lambda x: len(x) == 0)]
|
||||
empty_govs_task_df[GovsPushStatus.master_id.key] = empty_govs_task_df[GovsOrderMaster.id.key]
|
||||
empty_govs_task_df[GovsPushStatus.push_order_process_status.key] = 1
|
||||
empty_govs_task_df = empty_govs_task_df[
|
||||
[GovsPushStatus.master_id.key, GovsPushStatus.push_order_process_status.key]]
|
||||
await GovsPushStatus.save_batch(empty_govs_task_df)
|
||||
|
||||
# 过滤空数组
|
||||
full_govs_task_df = govs_task_df[govs_task_df['processLogBOList'].apply(lambda x: len(x) > 0)]
|
||||
|
||||
# 删除 processLogBOList内的工单id字段
|
||||
def remove_govs_task_id(data_list):
|
||||
for item in data_list:
|
||||
if isinstance(item, dict) and GovsOrderProcess.master_id.key in item:
|
||||
del item[GovsOrderProcess.master_id.key]
|
||||
return data_list
|
||||
|
||||
# 执行替换
|
||||
full_govs_task_df['processLogBOList'] = full_govs_task_df['processLogBOList'].apply(remove_govs_task_id)
|
||||
|
||||
# 处理数据映射,适应接口推送
|
||||
mapped_df = full_govs_task_df.rename(columns={GovsOrderMaster.id.key: 'gdId'})
|
||||
mapped_df['gdId'] = mapped_df['gdId'].astype(str)
|
||||
# 这里把空数据都换成 None,以便存入数据库时是 null
|
||||
mapped_df.replace(models.EmptyInDF + models.EmptyDatetimeInDF, '', inplace=True)
|
||||
|
||||
echo_log(f"正在准备请求队列...")
|
||||
# 构建请求队列
|
||||
push_queue = asyncio.Queue()
|
||||
|
||||
# 向队列中填充请求对象
|
||||
for _h, row in mapped_df.iterrows():
|
||||
row_data = row.to_dict()
|
||||
process_list = row_data['processLogBOList']
|
||||
for i in range(len(process_list)):
|
||||
attachment_list = process_list[i].get('fileIdList')
|
||||
if not attachment_list:
|
||||
process_list[i]['fileIdList'] = []
|
||||
else:
|
||||
if isinstance(attachment_list, str):
|
||||
try:
|
||||
attachment_list = json.loads(attachment_list)
|
||||
# 从省12345下载附件,然后上传到OA,获取id列表
|
||||
oa_file_ids = await download_and_upload_attachment(attachment_list)
|
||||
process_list[i]['fileIdList'] = oa_file_ids
|
||||
except Exception as e:
|
||||
echo_log(f'下载省12345的附件并上传到OA时遇到错误:{e}', is_log_exc=True)
|
||||
process_list[i]['fileIdList'] = []
|
||||
else:
|
||||
process_list[i]['fileIdList'] = []
|
||||
push_request = await oa_api_request.get_push_gov_process_request(**row_data)
|
||||
setattr(push_request, "govs_task_id", row.get('gdId'))
|
||||
await push_queue.put(push_request)
|
||||
|
||||
# 并发提交推送请求
|
||||
echo_log(f"开始推送待办过程数据...")
|
||||
pushed_task_ids = await requests.async_concurrency(
|
||||
push_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
|
||||
after_request=after_push_order_process_request, after_done=done_push_order_process
|
||||
)
|
||||
echo_log(f"待办过程数据推送已经完成...")
|
||||
return pushed_task_ids
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from paste.core import aio_pool
|
||||
|
||||
_runner = aio_pool.get_aio_runner()
|
||||
_runner(push_order_process(fetch_size=60))
|
||||
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
向 OA 平台上报数据已经完整推送。
|
||||
|
||||
对应文档接口:8、签收
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Optional, Union
|
||||
|
||||
from sqlalchemy import select, desc
|
||||
from tornado.httpclient import HTTPResponse, HTTPRequest
|
||||
|
||||
import dock
|
||||
from dock.oa import oa_api_request
|
||||
from models.govs_push_status import GovsPushStatus
|
||||
from models.govs_order_master import GovsOrderMaster
|
||||
from paste.core.logging import echo_log
|
||||
from paste.util import udict
|
||||
from paste.web import requests
|
||||
|
||||
|
||||
async def after_sign_task_request(response: HTTPResponse, retry_queue: asyncio.Queue[HTTPRequest]):
|
||||
"""
|
||||
签收工单请求响应后的处理程序。
|
||||
|
||||
:param response: 响应对象
|
||||
:param retry_queue: 重试队列
|
||||
"""
|
||||
body = response.body.decode()
|
||||
echo_log(body)
|
||||
body_data = json.loads(body)
|
||||
code = udict.get_by_path(body_data, 'code')
|
||||
message = udict.get_by_path(body_data, 'msg')
|
||||
if code == 200:
|
||||
echo_log(f"签收工单成功.")
|
||||
else:
|
||||
echo_log(f"签收工单失败:{message}")
|
||||
|
||||
if retry_queue:
|
||||
echo_log(f"签收工单重试队列中有:{retry_queue.qsize()} 个请求在等待.")
|
||||
|
||||
|
||||
async def sign_task(fetch_size: int = 50,
|
||||
task_id: Optional[Union[str, int, list[Union[str, int]]]] = None):
|
||||
"""
|
||||
签收指定数量的工单任务,或签收指定id的工单
|
||||
|
||||
:param fetch_size: 本次签收的任务数量
|
||||
:param task_id: 待办任务 ID 可选
|
||||
"""
|
||||
# 根据条件获取目标任务 ID 列表(支持指定 task_id 或分页获取)
|
||||
task_query = select(GovsOrderMaster.id).join(
|
||||
GovsPushStatus, GovsPushStatus.master_id == GovsOrderMaster.id
|
||||
).where(
|
||||
GovsPushStatus.push_order_status == 1,
|
||||
GovsPushStatus.push_order_detail_status == 1,
|
||||
GovsPushStatus.push_order_process_status == 1
|
||||
).order_by(
|
||||
desc(GovsOrderMaster.id)
|
||||
)
|
||||
if task_id is not None:
|
||||
if isinstance(task_id, list):
|
||||
task_query = task_query.where(GovsOrderMaster.id.in_(task_id))
|
||||
echo_log(f"本次签收待办列表:{task_id} 的工单...")
|
||||
else:
|
||||
task_query = task_query.where(GovsOrderMaster.id == task_id)
|
||||
echo_log(f"本次签收待办:{task_id} 的工单...")
|
||||
else:
|
||||
task_query = task_query.limit(fetch_size)
|
||||
echo_log(f"本次签收前 {fetch_size} 条待办工单...")
|
||||
|
||||
govs_task_df = await GovsOrderMaster.query_as_df(task_query)
|
||||
# 格式化为字符串
|
||||
govs_task_df[GovsOrderMaster.id.key] = govs_task_df[GovsOrderMaster.id.key].astype(str)
|
||||
|
||||
echo_log(f"正在准备请求队列...")
|
||||
# 构建请求队列
|
||||
sign_request_queue = asyncio.Queue()
|
||||
task_id_list = govs_task_df[GovsOrderMaster.id.key].unique().tolist()
|
||||
for task_id in task_id_list:
|
||||
request = await oa_api_request.get_sign_govs_task_request(task_id)
|
||||
await sign_request_queue.put(request)
|
||||
echo_log(f"开始签收工单...")
|
||||
await requests.async_concurrency(
|
||||
sign_request_queue, con_count=dock.CONCURRENCY_COUNT, retry=dock.MAX_RETRY_COUNT,
|
||||
after_request=after_sign_task_request
|
||||
)
|
||||
echo_log(f"签收工单完成...")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from paste.core import aio_pool
|
||||
|
||||
_runner = aio_pool.get_aio_runner()
|
||||
_runner(sign_task(task_id=2057694366475214849))
|
||||
Reference in New Issue
Block a user