"""Work Record API routes.""" from flask import request from flask_restx import Namespace, Resource, fields from app.services.work_record_service import WorkRecordService from app.utils.auth_decorator import require_auth work_record_ns = Namespace('work-records', description='工作记录管理接口') # API models for Swagger documentation work_record_model = work_record_ns.model('WorkRecord', { 'id': fields.Integer(readonly=True, description='记录ID'), 'person_id': fields.Integer(required=True, description='人员ID'), 'person_name': fields.String(readonly=True, description='人员姓名'), 'item_id': fields.Integer(required=True, description='物品ID'), 'item_name': fields.String(readonly=True, description='物品名称'), 'unit_price': fields.Float(readonly=True, description='单价'), 'work_date': fields.String(required=True, description='工作日期 (YYYY-MM-DD)'), 'quantity': fields.Integer(required=True, description='数量'), 'total_price': fields.Float(readonly=True, description='总价'), 'created_at': fields.String(readonly=True, description='创建时间'), 'updated_at': fields.String(readonly=True, description='更新时间') }) work_record_input = work_record_ns.model('WorkRecordInput', { 'person_id': fields.Integer(required=True, description='人员ID'), 'item_id': fields.Integer(required=True, description='物品ID'), 'work_date': fields.String(required=True, description='工作日期 (YYYY-MM-DD)'), 'quantity': fields.Integer(required=True, description='数量') }) work_record_update = work_record_ns.model('WorkRecordUpdate', { 'id': fields.Integer(required=True, description='记录ID'), 'person_id': fields.Integer(description='人员ID'), 'item_id': fields.Integer(description='物品ID'), 'work_date': fields.String(description='工作日期 (YYYY-MM-DD)'), 'quantity': fields.Integer(description='数量') }) work_record_delete = work_record_ns.model('WorkRecordDelete', { 'id': fields.Integer(required=True, description='记录ID') }) # Response models success_response = work_record_ns.model('SuccessResponse', { 'success': fields.Boolean(description='操作是否成功'), 'data': fields.Raw(description='返回数据'), 'message': fields.String(description='消息') }) error_response = work_record_ns.model('ErrorResponse', { 'success': fields.Boolean(description='操作是否成功'), 'error': fields.String(description='错误信息'), 'code': fields.String(description='错误代码') }) # Daily summary models daily_summary_item = work_record_ns.model('DailySummaryItem', { 'item_name': fields.String(description='物品名称'), 'unit_price': fields.Float(description='单价'), 'quantity': fields.Integer(description='数量'), 'total_price': fields.Float(description='总价') }) daily_summary_person = work_record_ns.model('DailySummaryPerson', { 'person_id': fields.Integer(description='人员ID'), 'person_name': fields.String(description='人员姓名'), 'total_items': fields.Integer(description='总数量'), 'total_value': fields.Float(description='总金额'), 'items': fields.List(fields.Nested(daily_summary_item), description='物品明细') }) daily_summary_response = work_record_ns.model('DailySummaryResponse', { 'date': fields.String(description='日期'), 'summary': fields.List(fields.Nested(daily_summary_person), description='人员汇总'), 'grand_total_items': fields.Integer(description='总数量'), 'grand_total_value': fields.Float(description='总金额') }) # Monthly summary models monthly_top_performer = work_record_ns.model('MonthlyTopPerformer', { 'person_id': fields.Integer(description='人员ID'), 'person_name': fields.String(description='人员姓名'), 'earnings': fields.Float(description='收入') }) monthly_item_breakdown = work_record_ns.model('MonthlyItemBreakdown', { 'item_id': fields.Integer(description='物品ID'), 'item_name': fields.String(description='物品名称'), 'quantity': fields.Integer(description='数量'), 'earnings': fields.Float(description='收入') }) monthly_summary_response = work_record_ns.model('MonthlySummaryResponse', { 'year': fields.Integer(description='年份'), 'month': fields.Integer(description='月份'), 'total_records': fields.Integer(description='总记录数'), 'total_earnings': fields.Float(description='总收入'), 'top_performers': fields.List(fields.Nested(monthly_top_performer), description='业绩排名'), 'item_breakdown': fields.List(fields.Nested(monthly_item_breakdown), description='物品收入明细') }) @work_record_ns.route('') class WorkRecordList(Resource): """Resource for listing work records with filters.""" @work_record_ns.doc('list_work_records') @work_record_ns.param('person_id', '按人员ID筛选', type=int) @work_record_ns.param('date', '按具体日期筛选 (YYYY-MM-DD)', type=str) @work_record_ns.param('year', '按年份筛选 (如 2024)', type=int) @work_record_ns.param('month', '按月份筛选 (1-12)', type=int) @work_record_ns.param('start_date', '开始日期 (YYYY-MM-DD)', type=str) @work_record_ns.param('end_date', '结束日期 (YYYY-MM-DD)', type=str) @work_record_ns.response(200, 'Success', success_response) @require_auth def get(self): """获取工作记录列表(支持筛选)""" person_id = request.args.get('person_id', type=int) date = request.args.get('date') year = request.args.get('year', type=int) month = request.args.get('month', type=int) start_date = request.args.get('start_date') end_date = request.args.get('end_date') # 如果指定了具体日期,使用 start_date 和 end_date 来筛选同一天 if date: start_date = date end_date = date work_records = WorkRecordService.get_all( person_id=person_id, start_date=start_date, end_date=end_date, year=year, month=month ) return { 'success': True, 'data': work_records, 'message': 'Work records retrieved successfully' }, 200 @work_record_ns.route('/') @work_record_ns.param('id', '记录ID') class WorkRecordDetail(Resource): """Resource for getting a single work record.""" @work_record_ns.doc('get_work_record') @work_record_ns.response(200, 'Success', success_response) @work_record_ns.response(404, 'Work record not found', error_response) @require_auth def get(self, id): """根据ID获取工作记录""" work_record, error = WorkRecordService.get_by_id(id) if error: return { 'success': False, 'error': error, 'code': 'NOT_FOUND' }, 404 return { 'success': True, 'data': work_record, 'message': 'Work record retrieved successfully' }, 200 @work_record_ns.route('/create') class WorkRecordCreate(Resource): """Resource for creating a work record.""" @work_record_ns.doc('create_work_record') @work_record_ns.expect(work_record_input) @work_record_ns.response(200, 'Success', success_response) @work_record_ns.response(400, 'Validation error', error_response) @work_record_ns.response(404, 'Reference not found', error_response) @require_auth def post(self): """创建新工作记录""" data = work_record_ns.payload person_id = data.get('person_id') item_id = data.get('item_id') work_date = data.get('work_date') quantity = data.get('quantity') work_record, error = WorkRecordService.create( person_id=person_id, item_id=item_id, work_date=work_date, quantity=quantity ) if error: if 'not found' in error.lower(): return { 'success': False, 'error': error, 'code': 'REFERENCE_ERROR' }, 404 return { 'success': False, 'error': error, 'code': 'VALIDATION_ERROR' }, 400 return { 'success': True, 'data': work_record, 'message': 'Work record created successfully' }, 200 @work_record_ns.route('/update') class WorkRecordUpdate(Resource): """Resource for updating a work record.""" @work_record_ns.doc('update_work_record') @work_record_ns.expect(work_record_update) @work_record_ns.response(200, 'Success', success_response) @work_record_ns.response(400, 'Validation error', error_response) @work_record_ns.response(404, 'Not found', error_response) @require_auth def post(self): """更新工作记录""" data = work_record_ns.payload work_record_id = data.get('id') if not work_record_id: return { 'success': False, 'error': 'Work record ID is required', 'code': 'VALIDATION_ERROR' }, 400 work_record, error = WorkRecordService.update( work_record_id=work_record_id, person_id=data.get('person_id'), item_id=data.get('item_id'), work_date=data.get('work_date'), quantity=data.get('quantity') ) if error: if 'not found' in error.lower(): return { 'success': False, 'error': error, 'code': 'NOT_FOUND' }, 404 return { 'success': False, 'error': error, 'code': 'VALIDATION_ERROR' }, 400 return { 'success': True, 'data': work_record, 'message': 'Work record updated successfully' }, 200 @work_record_ns.route('/delete') class WorkRecordDelete(Resource): """Resource for deleting a work record.""" @work_record_ns.doc('delete_work_record') @work_record_ns.expect(work_record_delete) @work_record_ns.response(200, 'Success', success_response) @work_record_ns.response(404, 'Work record not found', error_response) @require_auth def post(self): """删除工作记录""" data = work_record_ns.payload work_record_id = data.get('id') if not work_record_id: return { 'success': False, 'error': 'Work record ID is required', 'code': 'VALIDATION_ERROR' }, 400 success, error = WorkRecordService.delete(work_record_id) if error: return { 'success': False, 'error': error, 'code': 'NOT_FOUND' }, 404 return { 'success': True, 'data': None, 'message': 'Work record deleted successfully' }, 200 @work_record_ns.route('/daily-summary') class WorkRecordDailySummary(Resource): """Resource for getting daily summary.""" @work_record_ns.doc('get_daily_summary') @work_record_ns.param('date', '日期 (YYYY-MM-DD)', required=True, type=str) @work_record_ns.param('person_id', '按人员ID筛选', type=int) @work_record_ns.response(200, 'Success') @work_record_ns.response(400, 'Validation error', error_response) @require_auth def get(self): """获取每日工作汇总""" work_date = request.args.get('date') person_id = request.args.get('person_id', type=int) if not work_date: return { 'success': False, 'error': 'Date parameter is required', 'code': 'VALIDATION_ERROR' }, 400 try: summary = WorkRecordService.get_daily_summary( work_date=work_date, person_id=person_id ) return { 'success': True, 'data': summary, 'message': 'Daily summary retrieved successfully' }, 200 except ValueError as e: return { 'success': False, 'error': str(e), 'code': 'VALIDATION_ERROR' }, 400 @work_record_ns.route('/monthly-summary') class WorkRecordMonthlySummary(Resource): """Resource for getting monthly summary.""" @work_record_ns.doc('get_monthly_summary') @work_record_ns.param('year', '年份 (如 2024)', required=True, type=int) @work_record_ns.param('month', '月份 (1-12)', required=True, type=int) @work_record_ns.response(200, 'Success') @work_record_ns.response(400, 'Validation error', error_response) @require_auth def get(self): """获取月度工作汇总""" year = request.args.get('year', type=int) month = request.args.get('month', type=int) if not year or not month: return { 'success': False, 'error': 'Year and month parameters are required', 'code': 'VALIDATION_ERROR' }, 400 if month < 1 or month > 12: return { 'success': False, 'error': 'Month must be between 1 and 12', 'code': 'VALIDATION_ERROR' }, 400 try: summary = WorkRecordService.get_monthly_summary( year=year, month=month ) return { 'success': True, 'data': summary, 'message': 'Monthly summary retrieved successfully' }, 200 except ValueError as e: return { 'success': False, 'error': str(e), 'code': 'VALIDATION_ERROR' }, 400