auto_generate_plans.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. """地磅计划按月自动生成 — 迁移自 simple-dibang-xiaoshou/auto-create-plan/auto_create_monthly_plan.py"""
  2. from __future__ import annotations
  3. import logging
  4. from datetime import date, datetime, timedelta
  5. from sqlalchemy import and_, or_
  6. from sqlalchemy.orm import Session
  7. from app.core.utils import generate_uuid
  8. from app.models.db_models import DbPurchasePlan
  9. from app.services.db.plan_helpers import default_execution_status, generate_plan_no
  10. logger = logging.getLogger(__name__)
  11. def month_range(dt: date) -> tuple[date, date]:
  12. """返回 dt 所在月份的首日、末日。"""
  13. first = dt.replace(day=1)
  14. if first.month == 12:
  15. next_month = first.replace(year=first.year + 1, month=1, day=1)
  16. else:
  17. next_month = first.replace(month=first.month + 1, day=1)
  18. last = next_month - timedelta(days=1)
  19. return first, last
  20. def get_last_month_range(now: date) -> tuple[date, date]:
  21. """返回上个月的首日、末日。"""
  22. first_this, _ = month_range(now)
  23. last_prev = first_this - timedelta(days=1)
  24. return month_range(last_prev)
  25. def run_auto_generate_monthly_plans(
  26. db: Session,
  27. *,
  28. force: bool = False,
  29. now: date | None = None,
  30. ) -> dict:
  31. """
  32. 按月自动生成采购计划。
  33. - 默认仅在每月 1 日执行(force=True 时跳过该限制,供手动触发验收)
  34. - 遍历所有租户,按上月计划模板生成本月计划
  35. """
  36. today = now or date.today()
  37. if today.day != 1 and not force:
  38. logger.info("当前不是每月 1 日且未 force,跳过自动生成计划")
  39. return {
  40. "created_count": 0,
  41. "skipped_reason": "not_first_day_of_month",
  42. "current_month": today.strftime("%Y-%m"),
  43. }
  44. current_month = today.strftime("%Y-%m")
  45. this_month_first, this_month_last = month_range(today)
  46. last_month_first, last_month_last = get_last_month_range(today)
  47. logger.info(
  48. "开始执行自动生成计划任务,current_month=%s, last_month=[%s, %s], this_month=[%s, %s], force=%s",
  49. current_month,
  50. last_month_first,
  51. last_month_last,
  52. this_month_first,
  53. this_month_last,
  54. force,
  55. )
  56. plans = (
  57. db.query(DbPurchasePlan)
  58. .filter(
  59. and_(
  60. DbPurchasePlan.del_flag == 0,
  61. DbPurchasePlan.auto_generate_enabled == 1,
  62. or_(
  63. DbPurchasePlan.auto_generate_last_month.is_(None),
  64. DbPurchasePlan.auto_generate_last_month != current_month,
  65. ),
  66. or_(
  67. DbPurchasePlan.auto_generate_end_month.is_(None),
  68. DbPurchasePlan.auto_generate_end_month >= current_month,
  69. ),
  70. DbPurchasePlan.start_date == last_month_first,
  71. DbPurchasePlan.end_date == last_month_last,
  72. )
  73. )
  74. .all()
  75. )
  76. if not plans:
  77. logger.info("未找到需要自动生成下月计划的记录")
  78. return {
  79. "created_count": 0,
  80. "skipped_reason": None,
  81. "current_month": current_month,
  82. }
  83. logger.info("找到 %d 条可自动生成的上月计划", len(plans))
  84. created_count = 0
  85. for source in plans:
  86. new_plan = DbPurchasePlan(
  87. id=generate_uuid(),
  88. tenant_no=source.tenant_no,
  89. plan_no=generate_plan_no(),
  90. plan_date=this_month_first,
  91. start_date=this_month_first,
  92. end_date=this_month_last,
  93. business_type=source.business_type,
  94. product_id=source.product_id,
  95. product=source.product,
  96. specification=source.specification,
  97. planned_quantity=source.planned_quantity,
  98. vehicle_no=source.vehicle_no or "",
  99. customer_name=source.customer_name,
  100. remark=source.remark,
  101. execution_status=default_execution_status(source.business_type),
  102. executed_at=None,
  103. last_weighing_slip_id=None,
  104. executed_quantity=0,
  105. auto_generate_enabled=source.auto_generate_enabled,
  106. auto_generate_end_month=source.auto_generate_end_month,
  107. auto_generate_last_month=None,
  108. create_by=None,
  109. create_dept_id="",
  110. )
  111. db.add(new_plan)
  112. source.auto_generate_last_month = current_month
  113. created_count += 1
  114. db.commit()
  115. logger.info("本次自动生成完成,共生成 %d 条新计划", created_count)
  116. return {
  117. "created_count": created_count,
  118. "skipped_reason": None,
  119. "current_month": current_month,
  120. }