item_service.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. """Item service for business logic operations."""
  2. from sqlalchemy.exc import IntegrityError
  3. from app import db
  4. from app.models.item import Item
  5. from app.models.supplier import Supplier
  6. from app.utils.validators import is_valid_name, is_positive_number
  7. class ItemService:
  8. """Service class for Item CRUD operations."""
  9. @staticmethod
  10. def create(name, unit_price, supplier_id=None):
  11. """Create a new item.
  12. Args:
  13. name: Item's name
  14. unit_price: Price per unit
  15. supplier_id: Optional supplier ID
  16. Returns:
  17. Tuple of (item_dict, error_message)
  18. On success: (item_dict, None)
  19. On failure: (None, error_message)
  20. """
  21. if not is_valid_name(name):
  22. return None, "物品名称不能为空"
  23. if not is_positive_number(unit_price):
  24. return None, "单价必须为正数"
  25. # Check for duplicate name
  26. existing = Item.query.filter(Item.name == name.strip()).first()
  27. if existing:
  28. return None, "物品名称已存在"
  29. # Validate supplier_id if provided
  30. if supplier_id is not None:
  31. supplier = db.session.get(Supplier, supplier_id)
  32. if not supplier:
  33. return None, f"未找到ID为 {supplier_id} 的供应商"
  34. try:
  35. item = Item(name=name.strip(), unit_price=float(unit_price), supplier_id=supplier_id)
  36. db.session.add(item)
  37. db.session.commit()
  38. return item.to_dict(), None
  39. except IntegrityError:
  40. db.session.rollback()
  41. return None, "物品名称已存在"
  42. @staticmethod
  43. def get_all():
  44. """Get all items.
  45. Returns:
  46. List of item dictionaries
  47. """
  48. items = Item.query.order_by(Item.id).all()
  49. return [i.to_dict() for i in items]
  50. @staticmethod
  51. def get_by_id(item_id):
  52. """Get an item by ID.
  53. Args:
  54. item_id: Item's ID
  55. Returns:
  56. Tuple of (item_dict, error_message)
  57. On success: (item_dict, None)
  58. On failure: (None, error_message)
  59. """
  60. item = db.session.get(Item, item_id)
  61. if not item:
  62. return None, f"未找到ID为 {item_id} 的物品"
  63. return item.to_dict(), None
  64. @staticmethod
  65. def update(item_id, name=None, unit_price=None, supplier_id=None):
  66. """Update an item's name, unit_price, and/or supplier_id.
  67. Args:
  68. item_id: Item's ID
  69. name: New name (optional)
  70. unit_price: New unit price (optional)
  71. supplier_id: New supplier ID (optional, use -1 to clear)
  72. Returns:
  73. Tuple of (item_dict, error_message)
  74. On success: (item_dict, None)
  75. On failure: (None, error_message)
  76. """
  77. item = db.session.get(Item, item_id)
  78. if not item:
  79. return None, f"未找到ID为 {item_id} 的物品"
  80. if name is not None:
  81. if not is_valid_name(name):
  82. return None, "物品名称不能为空"
  83. # Check for duplicate name (excluding current item)
  84. existing = Item.query.filter(
  85. Item.name == name.strip(),
  86. Item.id != item_id
  87. ).first()
  88. if existing:
  89. return None, "物品名称已存在"
  90. item.name = name.strip()
  91. if unit_price is not None:
  92. if not is_positive_number(unit_price):
  93. return None, "单价必须为正数"
  94. item.unit_price = float(unit_price)
  95. # Handle supplier_id update
  96. if supplier_id is not None:
  97. if supplier_id == -1 or supplier_id == '':
  98. # Clear supplier
  99. item.supplier_id = None
  100. else:
  101. # Validate supplier exists
  102. supplier = db.session.get(Supplier, supplier_id)
  103. if not supplier:
  104. return None, f"未找到ID为 {supplier_id} 的供应商"
  105. item.supplier_id = supplier_id
  106. try:
  107. db.session.commit()
  108. return item.to_dict(), None
  109. except IntegrityError:
  110. db.session.rollback()
  111. return None, "物品名称已存在"
  112. @staticmethod
  113. def delete(item_id):
  114. """Delete an item.
  115. Args:
  116. item_id: Item's ID
  117. Returns:
  118. Tuple of (success, error_message)
  119. On success: (True, None)
  120. On failure: (False, error_message)
  121. """
  122. item = db.session.get(Item, item_id)
  123. if not item:
  124. return False, f"未找到ID为 {item_id} 的物品"
  125. # Check if item has associated work records
  126. if item.work_records.count() > 0:
  127. return False, "无法删除已有工作记录的物品"
  128. db.session.delete(item)
  129. db.session.commit()
  130. return True, None