使用fastApi框架开发一个进销存管理系统来练习python

0 阅读9分钟

我们在学习编程的时候,需要找一些项目来练习自己掌握的编程基础知识,这篇文章给大家分享一个使用fastApi开发的一个进销存管理系统。这个项目写下来,对python的一些编程知识有了非常多的理解和体会。

使用的技术:

编程语言:

Python-3.12

后端:

FastApi框架

前端:

vue2 + element-ui

数据库:

mysql8.0

这个系统主要是练习web方向的开发。

主要实现的功能点有:系统管理、菜单管理、角色管理、账号管理、基础资料、商品档案、客户档案、供应商档案、仓库信息、员工管理、部门管理、报表分析、销售报表、采购报表、库存管理、出入库记录、采购管理、采购订单、采购入库、采购退货、销售管理、销售订单、销售出库、销售退货、首页、登录

因为最近有小伙伴说能不能写一些有管理权限的项目,那么这样的功能在这个项目里已经集成进来了,我们可以通过分配角色来控制账号可以看到哪些菜单~

项目结构截图:

image.png

部分代码分享:

from typing import Optional, List
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from core.response import ResponseModel
from core.exceptions import CustomException
from core.database import get_db
from models.employee import Employee
from models.department import Department
from schemas.employee import EmployeeCreate, EmployeeUpdate, EmployeeRequest, EmployeeResponse, EmployeeListResponse

router = APIRouter()

@router.get("/pageList")
async def get_employee_list(
    request: EmployeeRequest = Depends(),
    db: Session = Depends(get_db)
):
    """获取员工列表(分页)"""
    query = db.query(Employee).filter(Employee.isDeleted == 0)
    
    # 搜索条件
    if request.employeeName:
        query = query.filter(Employee.employeeName.like(f"%{request.employeeName}%"))
    if request.departmentId is not None:
        query = query.filter(Employee.departmentId == request.departmentId)
    
    # 按ID降序排序
    query = query.order_by(Employee.id.desc())
    
    total = query.count()
    employees = query.offset((request.pageNum - 1) * request.pageSize).limit(request.pageSize).all()
    
    # 关联查询部门名称
    records = []
    if employees:
        department_ids = [emp.departmentId for emp in employees if emp.departmentId is not None]
        
        department_map = {}
        if department_ids:
            departments = db.query(Department).filter(
                Department.id.in_(department_ids),
                Department.isDeleted == 0
            ).all()
            department_map = {dept.id: dept.departmentName for dept in departments}
        
        for emp in employees:
            emp_dict = EmployeeResponse.model_validate(emp).model_dump()
            if emp.departmentId is not None:
                emp_dict['departmentName'] = department_map.get(emp.departmentId)
            records.append(EmployeeResponse(**emp_dict))
    
    response = EmployeeListResponse(total=total, records=records)
    return ResponseModel.success(data=response.model_dump())

@router.get("/list")
async def get_employee_list_all(
    db: Session = Depends(get_db)
):
    """获取所有员工列表(不分页)"""
    query = db.query(Employee).filter(Employee.isDeleted == 0)
    query = query.order_by(Employee.id.desc())
    employees = query.all()
    
    # 关联查询部门名称
    records = []
    if employees:
        department_ids = [emp.departmentId for emp in employees if emp.departmentId is not None]
        
        department_map = {}
        if department_ids:
            departments = db.query(Department).filter(
                Department.id.in_(department_ids),
                Department.isDeleted == 0
            ).all()
            department_map = {dept.id: dept.departmentName for dept in departments}
        
        for emp in employees:
            emp_dict = EmployeeResponse.model_validate(emp).model_dump()
            if emp.departmentId is not None:
                emp_dict['departmentName'] = department_map.get(emp.departmentId)
            records.append(EmployeeResponse(**emp_dict))
    
    return ResponseModel.success(data=[record.model_dump() for record in records])

@router.post("/add")
async def add_employee(
    employee_in: EmployeeCreate,
    db: Session = Depends(get_db)
):
    """添加员工"""
    # 参数校验
    if not employee_in.employeeName:
        raise CustomException(msg="员工姓名不能为空")
    if not employee_in.employeeCode:
        raise CustomException(msg="员工编号不能为空")
    if employee_in.departmentId is None:
        raise CustomException(msg="部门不能为空")
    
    # 检查员工编号是否已存在
    exist_emp = db.query(Employee).filter(
        Employee.employeeCode == employee_in.employeeCode,
        Employee.isDeleted == 0
    ).first()
    if exist_emp:
        raise CustomException(msg="员工编号已存在")
    
    # 如果设置为部门负责人,检查该部门是否已有负责人
    if employee_in.isManager == 1:
        old_managers = db.query(Employee).filter(
            Employee.departmentId == employee_in.departmentId,
            Employee.isManager == 1,
            Employee.isDeleted == 0
        ).all()
        if old_managers:
            # 将原负责人的is_manager字段改为0
            for old_manager in old_managers:
                old_manager.isManager = 0
    
    # 保存员工信息
    employee = Employee(
        employeeName=employee_in.employeeName,
        employeeCode=employee_in.employeeCode,
        departmentId=employee_in.departmentId,
        position=employee_in.position,
        contactPhone=employee_in.contactPhone,
        hireDate=employee_in.hireDate,
        status=employee_in.status,
        isManager=employee_in.isManager,
        remark=employee_in.remark
    )
    db.add(employee)
    db.commit()
    db.refresh(employee)
    
    # 只有设置为负责人时,才更新部门表的负责人ID和联系电话
    if employee_in.isManager == 1:
        update_department_manager(db, employee)
    
    return ResponseModel.success(msg="添加成功")

@router.put("/updateEmployee")
async def update_employee(
    employee_in: EmployeeUpdate,
    db: Session = Depends(get_db)
):
    """更新员工信息"""
    # 参数校验
    if not employee_in.id:
        raise CustomException(msg="员工ID不能为空")
    if not employee_in.employeeName:
        raise CustomException(msg="员工姓名不能为空")
    if not employee_in.employeeCode:
        raise CustomException(msg="员工编号不能为空")
    if employee_in.departmentId is None:
        raise CustomException(msg="部门不能为空")
    
    # 获取原员工信息
    exist_employee = db.query(Employee).filter(
        Employee.id == employee_in.id,
        Employee.isDeleted == 0
    ).first()
    if not exist_employee:
        raise CustomException(msg="员工不存在")
    
    # 如果修改了员工编号,检查是否已存在
    if employee_in.employeeCode != exist_employee.employeeCode:
        code_exist = db.query(Employee).filter(
            Employee.employeeCode == employee_in.employeeCode,
            Employee.id != employee_in.id,
            Employee.isDeleted == 0
        ).first()
        if code_exist:
            raise CustomException(msg="员工编号已存在")
    
    # 如果设置为部门负责人,检查该部门是否已有负责人
    if employee_in.isManager == 1:
        old_managers = db.query(Employee).filter(
            Employee.departmentId == employee_in.departmentId,
            Employee.isManager == 1,
            Employee.id != employee_in.id,
            Employee.isDeleted == 0
        ).all()
        if old_managers:
            # 将原负责人的is_manager字段改为0
            for old_manager in old_managers:
                old_manager.isManager = 0
    
    # 更新员工信息
    exist_employee.employeeName = employee_in.employeeName
    exist_employee.employeeCode = employee_in.employeeCode
    exist_employee.departmentId = employee_in.departmentId
    exist_employee.position = employee_in.position
    exist_employee.contactPhone = employee_in.contactPhone
    exist_employee.hireDate = employee_in.hireDate
    exist_employee.status = employee_in.status
    exist_employee.isManager = employee_in.isManager
    exist_employee.remark = employee_in.remark
    
    db.commit()
    
    # 处理负责人逻辑
    handle_department_manager(db, exist_employee, employee_in)
    
    return ResponseModel.success(msg="更新成功")

@router.delete("/deleteEmployee")
async def delete_employee(
    id: int = Query(..., description='员工ID'),
    db: Session = Depends(get_db)
):
    """删除员工"""
    # 参数校验
    if not id:
        raise CustomException(msg="员工ID不能为空")
    
    # 获取员工信息
    employee = db.query(Employee).filter(
        Employee.id == id,
        Employee.isDeleted == 0
    ).first()
    if not employee:
        raise CustomException(msg="员工不存在")
    
    # 逻辑删除员工
    employee.isDeleted = 1
    db.commit()
    
    # 如果该员工是部门负责人,清空部门的负责人信息
    if employee.isManager == 1 and employee.departmentId is not None:
        department = db.query(Department).filter(
            Department.id == employee.departmentId,
            Department.isDeleted == 0
        ).first()
        if department and department.employeeId is not None and department.employeeId == employee.id:
            department.employeeId = None
            department.contactPhone = None
            db.commit()
    
    return ResponseModel.success(msg="删除成功")

def handle_department_manager(db: Session, exist_employee: Employee, employee_in: EmployeeUpdate):
    """处理部门负责人逻辑"""
    # 处理新部门的负责人逻辑
    if employee_in.isManager == 1:
        # 设置为负责人,更新部门表的负责人ID和联系电话
        update_department_manager(db, exist_employee)
    elif exist_employee.isManager == 1:
        # 原来是负责人,现在不是,需要清空部门的负责人信息
        old_department = db.query(Department).filter(
            Department.id == exist_employee.departmentId,
            Department.isDeleted == 0
        ).first()
        if old_department and old_department.employeeId is not None and old_department.employeeId == exist_employee.id:
            old_department.employeeId = None
            old_department.contactPhone = None
            db.commit()

def update_department_manager(db: Session, employee: Employee):
    """更新部门表的负责人ID和联系电话"""
    if employee.departmentId is not None:
        department = db.query(Department).filter(
            Department.id == employee.departmentId,
            Department.isDeleted == 0
        ).first()
        if department:
            department.employeeId = employee.id
            department.contactPhone = employee.contactPhone
            db.commit()
from typing import Optional, List
from datetime import datetime
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from decimal import Decimal
from core.response import ResponseModel
from core.exceptions import CustomException
from core.database import get_db
from models.purchase_return import PurchaseReturn
from models.purchase_return_detail import PurchaseReturnDetail
from models.supplier import Supplier
from models.employee import Employee
from models.product import Product
from models.purchase_inbound import PurchaseInbound
from models.inventory_record import InventoryRecord
from schemas.purchase_return import (
    PurchaseReturnCreate, PurchaseReturnUpdate, PurchaseReturnRequest, 
    PurchaseReturnResponse, PurchaseReturnListResponse,
    PurchaseReturnDetailCreate, PurchaseReturnDetailUpdate, PurchaseReturnDetailResponse,
    get_return_status_name, get_refund_status_name
)

router = APIRouter()

@router.get("/pageList")
async def get_purchase_return_list(
    request: PurchaseReturnRequest = Depends(),
    db: Session = Depends(get_db)
):
    """获取采购退货列表(分页)"""
    query = db.query(PurchaseReturn).filter(PurchaseReturn.isDeleted == 0)
    
    # 搜索条件
    if request.returnNo:
        query = query.filter(PurchaseReturn.returnNo.like(f"%{request.returnNo}%"))
    
    # 按ID降序排序
    query = query.order_by(PurchaseReturn.id.desc())
    
    total = query.count()
    purchase_returns = query.offset((request.pageNum - 1) * request.pageSize).limit(request.pageSize).all()
    
    # 关联查询采购入库单编号、供应商名称、员工姓名
    records = []
    if purchase_returns:
        purchase_inbound_ids = [return_item.purchaseInboundId for return_item in purchase_returns if return_item.purchaseInboundId is not None]
        supplier_ids = [return_item.supplierId for return_item in purchase_returns if return_item.supplierId is not None]
        employee_ids = [return_item.employeeId for return_item in purchase_returns if return_item.employeeId is not None]
        
        purchase_inbound_map = {}
        if purchase_inbound_ids:
            purchase_inbounds = db.query(PurchaseInbound).filter(
                PurchaseInbound.id.in_(purchase_inbound_ids),
                PurchaseInbound.isDeleted == 0
            ).all()
            purchase_inbound_map = {pi.id: pi.inboundNo for pi in purchase_inbounds}
        
        supplier_map = {}
        if supplier_ids:
            suppliers = db.query(Supplier).filter(
                Supplier.id.in_(supplier_ids),
                Supplier.isDeleted == 0
            ).all()
            supplier_map = {sup.id: sup.supplierName for sup in suppliers}
        
        employee_map = {}
        if employee_ids:
            employees = db.query(Employee).filter(
                Employee.id.in_(employee_ids),
                Employee.isDeleted == 0
            ).all()
            employee_map = {emp.id: emp.employeeName for emp in employees}
        
        for return_item in purchase_returns:
            return_dict = PurchaseReturnResponse.model_validate(return_item).model_dump()
            if return_item.purchaseInboundId is not None:
                return_dict['purchaseInboundNo'] = purchase_inbound_map.get(return_item.purchaseInboundId)
            if return_item.supplierId is not None:
                return_dict['supplierName'] = supplier_map.get(return_item.supplierId)
            if return_item.employeeId is not None:
                return_dict['employeeName'] = employee_map.get(return_item.employeeId)
            # 设置退货状态名称
            return_dict['returnStatusName'] = get_return_status_name(return_item.returnStatus)
            # 设置退款状态名称
            return_dict['refundStatusName'] = get_refund_status_name(return_item.refundStatus)
            records.append(PurchaseReturnResponse(**return_dict))
    
    response = PurchaseReturnListResponse(total=total, records=records)
    return ResponseModel.success(data=response.model_dump())

@router.get("/list")
async def get_purchase_return_list_all(
    db: Session = Depends(get_db)
):
    """获取所有采购退货列表(不分页)"""
    query = db.query(PurchaseReturn).filter(PurchaseReturn.isDeleted == 0)
    query = query.order_by(PurchaseReturn.id.desc())
    purchase_returns = query.all()
    
    # 关联查询采购入库单编号、供应商名称、员工姓名
    records = []
    if purchase_returns:
        purchase_inbound_ids = [return_item.purchaseInboundId for return_item in purchase_returns if return_item.purchaseInboundId is not None]
        supplier_ids = [return_item.supplierId for return_item in purchase_returns if return_item.supplierId is not None]
        employee_ids = [return_item.employeeId for return_item in purchase_returns if return_item.employeeId is not None]
        
        purchase_inbound_map = {}
        if purchase_inbound_ids:
            purchase_inbounds = db.query(PurchaseInbound).filter(
                PurchaseInbound.id.in_(purchase_inbound_ids),
                PurchaseInbound.isDeleted == 0
            ).all()
            purchase_inbound_map = {pi.id: pi.inboundNo for pi in purchase_inbounds}
        
        supplier_map = {}
        if supplier_ids:
            suppliers = db.query(Supplier).filter(
                Supplier.id.in_(supplier_ids),
                Supplier.isDeleted == 0
            ).all()
            supplier_map = {sup.id: sup.supplierName for sup in suppliers}
        
        employee_map = {}
        if employee_ids:
            employees = db.query(Employee).filter(
                Employee.id.in_(employee_ids),
                Employee.isDeleted == 0
            ).all()
            employee_map = {emp.id: emp.employeeName for emp in employees}
        
        for return_item in purchase_returns:
            return_dict = PurchaseReturnResponse.model_validate(return_item).model_dump()
            if return_item.purchaseInboundId is not None:
                return_dict['purchaseInboundNo'] = purchase_inbound_map.get(return_item.purchaseInboundId)
            if return_item.supplierId is not None:
                return_dict['supplierName'] = supplier_map.get(return_item.supplierId)
            if return_item.employeeId is not None:
                return_dict['employeeName'] = employee_map.get(return_item.employeeId)
            # 设置退货状态名称
            return_dict['returnStatusName'] = get_return_status_name(return_item.returnStatus)
            # 设置退款状态名称
            return_dict['refundStatusName'] = get_refund_status_name(return_item.refundStatus)
            records.append(PurchaseReturnResponse(**return_dict))
    
    return ResponseModel.success(data=[record.model_dump() for record in records])

@router.get("/getByIdWithDetail")
async def get_purchase_return_with_detail(
    id: int = Query(..., description='采购退货ID'),
    db: Session = Depends(get_db)
):
    """获取采购退货详情(包含明细)"""
    purchase_return = db.query(PurchaseReturn).filter(
        PurchaseReturn.id == id,
        PurchaseReturn.isDeleted == 0
    ).first()
    if not purchase_return:
        raise CustomException(msg="采购退货不存在")
    
    # 关联查询采购入库单编号、供应商名称、员工姓名
    return_dict = PurchaseReturnResponse.model_validate(purchase_return).model_dump()
    if purchase_return.purchaseInboundId is not None:
        purchase_inbound = db.query(PurchaseInbound).filter(
            PurchaseInbound.id == purchase_return.purchaseInboundId,
            PurchaseInbound.isDeleted == 0
        ).first()
        if purchase_inbound:
            return_dict['purchaseInboundNo'] = purchase_inbound.inboundNo
    if purchase_return.supplierId is not None:
        supplier = db.query(Supplier).filter(
            Supplier.id == purchase_return.supplierId,
            Supplier.isDeleted == 0
        ).first()
        if supplier:
            return_dict['supplierName'] = supplier.supplierName
    if purchase_return.employeeId is not None:
        employee = db.query(Employee).filter(
            Employee.id == purchase_return.employeeId,
            Employee.isDeleted == 0
        ).first()
        if employee:
            return_dict['employeeName'] = employee.employeeName
    
    # 查询采购退货明细
    details = db.query(PurchaseReturnDetail).filter(
        PurchaseReturnDetail.purchaseReturnId == id,
        PurchaseReturnDetail.isDeleted == 0
    ).all()
    
    # 关联查询商品信息
    detail_list = []
    if details:
        product_ids = [detail.productId for detail in details if detail.productId is not None]
        
        product_map = {}
        if product_ids:
            products = db.query(Product).filter(
                Product.id.in_(product_ids),
                Product.isDeleted == 0
            ).all()
            product_map = {prod.id: prod for prod in products}
        
        for detail in details:
            detail_dict = PurchaseReturnDetailResponse.model_validate(detail).model_dump()
            if detail.productId is not None:
                product = product_map.get(detail.productId)
                if product:
                    detail_dict['productName'] = product.productName
                    detail_dict['productCode'] = product.productCode
                    detail_dict['specModel'] = product.specModel
                    detail_dict['unit'] = product.unit
            detail_list.append(PurchaseReturnDetailResponse(**detail_dict))
    
    return_dict['detailList'] = detail_list
    
    return ResponseModel.success(data=return_dict)

@router.post("/add")
async def add_purchase_return(
    return_in: PurchaseReturnCreate,
    db: Session = Depends(get_db)
):
    """添加采购退货"""
    # 参数校验
    if not return_in.returnNo:
        raise CustomException(msg="退货单编号不能为空")
    if return_in.purchaseInboundId is None:
        raise CustomException(msg="采购入库不能为空")
    if return_in.supplierId is None:
        raise CustomException(msg="供应商不能为空")
    if return_in.employeeId is None:
        raise CustomException(msg="员工不能为空")
    
    # 设置默认退货状态为未退货
    return_status = return_in.returnStatus if return_in.returnStatus is not None else 0
    
    # 设置默认退款状态为待退款
    refund_status = return_in.refundStatus if return_in.refundStatus is not None else 1
    
    # 保存采购退货主表
    purchase_return = PurchaseReturn(
        returnNo=return_in.returnNo,
        purchaseInboundId=return_in.purchaseInboundId,
        supplierId=return_in.supplierId,
        returnDate=return_in.returnDate,
        totalAmount=return_in.totalAmount,
        returnStatus=return_status,
        refundStatus=refund_status,
        employeeId=return_in.employeeId,
        remark=return_in.remark
    )
    db.add(purchase_return)
    db.commit()
    db.refresh(purchase_return)
    
    # 保存采购退货明细
    if return_in.detailList:
        for detail_in in return_in.detailList:
            detail = PurchaseReturnDetail(
                purchaseReturnId=purchase_return.id,
                productId=detail_in.productId,
                returnQuantity=detail_in.returnQuantity,
                purchasePrice=detail_in.purchasePrice,
                amount=detail_in.amount,
                remark=detail_in.remark
            )
            db.add(detail)
        db.commit()
    
    return ResponseModel.success(msg="添加成功")

@router.put("/updatePurchaseReturn")
async def update_purchase_return(
    return_in: PurchaseReturnUpdate,
    db: Session = Depends(get_db)
):
    """更新采购退货信息"""
    # 参数校验
    if not return_in.id:
        raise CustomException(msg="采购退货ID不能为空")
    if not return_in.returnNo:
        raise CustomException(msg="退货单编号不能为空")
    if return_in.purchaseInboundId is None:
        raise CustomException(msg="采购入库不能为空")
    if return_in.supplierId is None:
        raise CustomException(msg="供应商不能为空")
    if return_in.employeeId is None:
        raise CustomException(msg="员工不能为空")
    
    # 获取原采购退货信息
    exist_return = db.query(PurchaseReturn).filter(
        PurchaseReturn.id == return_in.id,
        PurchaseReturn.isDeleted == 0
    ).first()
    if not exist_return:
        raise CustomException(msg="采购退货不存在")
    
    # 更新采购退货主表
    exist_return.returnNo = return_in.returnNo
    exist_return.purchaseInboundId = return_in.purchaseInboundId
    exist_return.supplierId = return_in.supplierId
    exist_return.returnDate = return_in.returnDate
    exist_return.totalAmount = return_in.totalAmount
    exist_return.returnStatus = return_in.returnStatus
    exist_return.refundStatus = return_in.refundStatus
    exist_return.employeeId = return_in.employeeId
    exist_return.remark = return_in.remark
    db.commit()
    
    # 处理采购退货明细
    if return_in.detailList:
        # 获取当前采购退货的所有明细ID
        current_detail_ids = []
        for detail_in in return_in.detailList:
            if detail_in.id is not None:
                # 更新已有明细
                exist_detail = db.query(PurchaseReturnDetail).filter(
                    PurchaseReturnDetail.id == detail_in.id,
                    PurchaseReturnDetail.isDeleted == 0
                ).first()
                if exist_detail:
                    exist_detail.productId = detail_in.productId
                    exist_detail.returnQuantity = detail_in.returnQuantity
                    exist_detail.purchasePrice = detail_in.purchasePrice
                    exist_detail.amount = detail_in.amount
                    exist_detail.remark = detail_in.remark
                    current_detail_ids.append(exist_detail.id)
            else:
                # 新增明细
                detail = PurchaseReturnDetail(
                    purchaseReturnId=return_in.id,
                    productId=detail_in.productId,
                    returnQuantity=detail_in.returnQuantity,
                    purchasePrice=detail_in.purchasePrice,
                    amount=detail_in.amount,
                    remark=detail_in.remark
                )
                db.add(detail)
                db.commit()
                db.refresh(detail)
                current_detail_ids.append(detail.id)
        
        # 删除不在当前明细列表中的旧明细
        if current_detail_ids:
            db.query(PurchaseReturnDetail).filter(
                PurchaseReturnDetail.purchaseReturnId == return_in.id,
                PurchaseReturnDetail.isDeleted == 0,
                ~PurchaseReturnDetail.id.in_(current_detail_ids)
            ).delete(synchronize_session=False)
            db.commit()
    else:
        # 如果没有明细,删除所有明细
        db.query(PurchaseReturnDetail).filter(
            PurchaseReturnDetail.purchaseReturnId == return_in.id,
            PurchaseReturnDetail.isDeleted == 0
        ).delete(synchronize_session=False)
        db.commit()
    
    return ResponseModel.success(msg="更新成功")

@router.delete("/deletePurchaseReturn")
async def delete_purchase_return(
    id: int = Query(..., description='采购退货ID'),
    db: Session = Depends(get_db)
):
    """删除采购退货"""
    # 参数校验
    if not id:
        raise CustomException(msg="采购退货ID不能为空")
    
    # 删除采购退货明细
    db.query(PurchaseReturnDetail).filter(
        PurchaseReturnDetail.purchaseReturnId == id
    ).delete(synchronize_session=False)
    
    # 逻辑删除采购退货主表
    exist_return = db.query(PurchaseReturn).filter(
        PurchaseReturn.id == id,
        PurchaseReturn.isDeleted == 0
    ).first()
    if exist_return:
        exist_return.isDeleted = 1
        db.commit()
    
    return ResponseModel.success(msg="删除成功")

@router.post("/confirmReturn")
async def confirm_return(
    id: int = Query(..., description='采购退货ID'),
    db: Session = Depends(get_db)
):
    """确认退货"""
    # 参数校验
    if not id:
        raise CustomException(msg="采购退货ID不能为空")
    
    purchase_return = db.query(PurchaseReturn).filter(
        PurchaseReturn.id == id,
        PurchaseReturn.isDeleted == 0
    ).first()
    if not purchase_return:
        raise CustomException(msg="采购退货不存在")
    
    # 查询采购退货明细
    details = db.query(PurchaseReturnDetail).filter(
        PurchaseReturnDetail.purchaseReturnId == id,
        PurchaseReturnDetail.isDeleted == 0
    ).all()
    if not details:
        raise CustomException(msg="采购退货明细为空,无法确认退货")
    
    # 查询采购入库信息,获取仓库ID
    purchase_inbound = db.query(PurchaseInbound).filter(
        PurchaseInbound.id == purchase_return.purchaseInboundId,
        PurchaseInbound.isDeleted == 0
    ).first()
    if not purchase_inbound:
        raise CustomException(msg="采购入库不存在")
    
    # 创建出入库记录(出库)
    for detail in details:
        inventory_record = InventoryRecord(
            documentNo=purchase_return.returnNo,
            businessType="purchase_return",
            sourceDocumentId=purchase_return.id,
            productId=detail.productId,
            warehouseId=purchase_inbound.warehouseId,
            direction=2,
            quantity=detail.returnQuantity,
            price=detail.purchasePrice,
            amount=detail.purchasePrice * Decimal(detail.returnQuantity) if detail.purchasePrice and detail.returnQuantity else None,
            recordDate=purchase_return.returnDate,
            remark=purchase_return.remark
        )
        db.add(inventory_record)
    
    # 更新退货状态为已退货
    purchase_return.returnStatus = 1
    
    db.commit()
    
    return ResponseModel.success(msg="确认退货成功")

部分项目运行截图:

销售出库:

image.png

供应商档案:

image.png

角色管理:

image.png

如果你也刚刚开始学习python,正在迷茫需要写点什么项目来巩固自己的编程技术,那可以参考一下这个系统,可以仿照这个系统的功能,尝试着自己写写看,项目的预览地址已经发布上线了,有兴趣的小伙伴可以去看看: test.wwwoop.com/?s=jin-xiao…