From 4f90e02dcf41794f98144b9445b12677a7bc2752 Mon Sep 17 00:00:00 2001 From: dxc Date: Thu, 5 Feb 2026 14:36:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=B6=E9=97=B4=E6=97=B6?= =?UTF-8?q?=E5=8C=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/services/inbound/buy_service.py | 15 +++++++----- .../app/services/inbound/product_service.py | 10 ++++---- .../app/services/inbound/semi_service.py | 8 ++++--- .../app/services/outbound_service.py | 23 ++++++++++++++++--- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/inventory-backend/app/services/inbound/buy_service.py b/inventory-backend/app/services/inbound/buy_service.py index 3f41e34..e4b67f0 100644 --- a/inventory-backend/app/services/inbound/buy_service.py +++ b/inventory-backend/app/services/inbound/buy_service.py @@ -3,7 +3,7 @@ from app.extensions import db from app.models.inbound.buy import StockBuy from app.models.base import MaterialBase from app.models.outbound import TransOutbound -from datetime import datetime +from datetime import datetime, timedelta, timezone # [修改] 引入 timezone from sqlalchemy import or_, func, text, and_ import traceback import json @@ -40,7 +40,7 @@ class BuyInboundService: return [] # ============================================================ - # 2. 新增入库逻辑 (修改:精确到时间) + # 2. 新增入库逻辑 (强制北京时间) # ============================================================ @staticmethod def handle_inbound(data): @@ -51,8 +51,11 @@ class BuyInboundService: material = MaterialBase.query.get(base_id) if not material: raise ValueError("物料不存在") - # [核心修改] 默认使用当前时间(含时分秒),不再截取 .date() - current_time = datetime.now() + # [核心修改] 获取当前北京时间 (UTC+8) + # 无论服务器在 UTC 还是其他时区,这里强制转换为 UTC+8 并去掉时区信息存入数据库 + beijing_tz = timezone(timedelta(hours=8)) + current_time = datetime.now(beijing_tz).replace(tzinfo=None) + in_date_val = current_time if data.get('in_date'): @@ -62,12 +65,12 @@ class BuyInboundService: if len(date_str) > 10: in_date_val = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') else: - # 如果只传了日期,手动补上当前时间的时分秒,保证同日入库的排序正确 + # 如果只传了日期,使用该日期 + 当前北京时间的时分秒 d_temp = datetime.strptime(date_str, '%Y-%m-%d') in_date_val = datetime(d_temp.year, d_temp.month, d_temp.day, current_time.hour, current_time.minute, current_time.second) except: - # 解析失败则使用当前时间作为兜底 + # 解析失败则使用当前北京时间 in_date_val = current_time in_qty = float(data.get('in_quantity') or 0) diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index 1033578..101b3ff 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -2,7 +2,7 @@ from app.extensions import db from app.models.base import MaterialBase from app.models.outbound import TransOutbound -from datetime import datetime +from datetime import datetime, timedelta, timezone # [修改] from sqlalchemy import or_, func, text, and_ import traceback import json @@ -33,7 +33,7 @@ class ProductInboundService: return [] # ============================================================ - # 2. 新增入库逻辑 (修改:精确到时间) + # 2. 新增入库逻辑 (强制北京时间) # ============================================================ @staticmethod def handle_inbound(data): @@ -45,8 +45,10 @@ class ProductInboundService: material = MaterialBase.query.get(base_id) if not material: raise ValueError("物料不存在") - # [核心修改] 处理 production_date,包含时分秒 - current_time = datetime.now() + # [核心修改] 强制北京时间 + beijing_tz = timezone(timedelta(hours=8)) + current_time = datetime.now(beijing_tz).replace(tzinfo=None) + in_date_val = current_time if data.get('in_date'): diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index 6515e6e..40273b8 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -2,7 +2,7 @@ from app.extensions import db from app.models.base import MaterialBase from app.models.outbound import TransOutbound -from datetime import datetime +from datetime import datetime, timedelta, timezone # [修改] from sqlalchemy import or_, func, text, and_ import traceback import json @@ -52,8 +52,10 @@ class SemiInboundService: if not material: raise ValueError(f"ID为 {base_id} 的基础物料不存在") - # [核心修改] 处理入库日期(production_date),包含时分秒 - current_time = datetime.now() + # [核心修改] 强制北京时间 + beijing_tz = timezone(timedelta(hours=8)) + current_time = datetime.now(beijing_tz).replace(tzinfo=None) + in_date_val = current_time if data.get('in_date'): diff --git a/inventory-backend/app/services/outbound_service.py b/inventory-backend/app/services/outbound_service.py index a511f31..550e87a 100644 --- a/inventory-backend/app/services/outbound_service.py +++ b/inventory-backend/app/services/outbound_service.py @@ -1,5 +1,5 @@ import uuid -from datetime import datetime +from datetime import datetime, timezone, timedelta # [修改] 引入 timezone 和 timedelta from sqlalchemy import or_ from app.extensions import db from app.models.outbound import TransOutbound @@ -16,8 +16,15 @@ class OutboundService: @staticmethod def generate_outbound_no(): - """生成出库单号: OUT-yyyyMMdd-随机码""" - date_str = datetime.now().strftime('%Y%m%d') + """ + 生成出库单号: OUT-yyyyMMdd-随机码 + [修改] 强制使用北京时间生成日期前缀 + """ + # 获取北京时间 + beijing_tz = timezone(timedelta(hours=8)) + current_time = datetime.now(beijing_tz) + + date_str = current_time.strftime('%Y%m%d') short_uuid = uuid.uuid4().hex[:6].upper() return f"OUT-{date_str}-{short_uuid}" @@ -143,6 +150,12 @@ class OutboundService: stock_item.stock_quantity = float(stock_item.stock_quantity) - quantity stock_item.available_quantity = float(stock_item.available_quantity) - quantity + # [新增] 计算北京时间 + beijing_tz = timezone(timedelta(hours=8)) + # replace(tzinfo=None) 是为了让存入数据库的时间变为 naive time (不带时区信息的本地时间) + # 这样数据库看起来就是 "2023-10-27 15:00:00" 而不是 UTC 时间 + current_time = datetime.now(beijing_tz).replace(tzinfo=None) + # 5. 创建出库记录 new_outbound = TransOutbound( outbound_no=OutboundService.generate_outbound_no(), @@ -154,6 +167,10 @@ class OutboundService: quantity=quantity, consumer_name=data.get('consumer_name'), signature_path=data.get('signature_path'), # 存储签名的 URL + + # [关键] 显式设置北京时间,覆盖 Model 中的 default=datetime.now (UTC) + outbound_time=current_time, + operator_name=operator_name, remark=data.get('remark') )