feat(pl): wire deliveryTimeFrom/To through plan list and export
Contract-gap list/export share the same stop-date EXISTS filter. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
0e3df1f39d
commit
204b5f48c8
2 files changed
+52
-2
No files matched your search
@@ -117,6 +117,7 @@ from app.services.pl_plan_print_service import get_delivery_slip_print_context
|
||||
from app.services.pl_plan_stop_service import (
|
||||
attach_plan_stops_to_item,
|
||||
collect_stop_qty_warnings,
|
||||
collect_unique_delivery_date_strings,
|
||||
load_plan_stops_grouped,
|
||||
replace_plan_stops,
|
||||
sync_plan_legacy_from_stops,
|
||||
@@ -383,6 +384,8 @@ def _filters_from_params(params: dict, *, db: Session, tenant_no: str) -> list:
|
||||
license_plate=_param_get(params, "licensePlate", "license_plate"),
|
||||
plan_date_from=_param_get(params, "planDateFrom", "plan_date_from"),
|
||||
plan_date_to=_param_get(params, "planDateTo", "plan_date_to"),
|
||||
delivery_time_from=_param_get(params, "deliveryTimeFrom", "delivery_time_from"),
|
||||
delivery_time_to=_param_get(params, "deliveryTimeTo", "delivery_time_to"),
|
||||
cert_upload_status=_param_get(params, "certUploadStatus", "cert_upload_status"),
|
||||
hazard_cert_ready=_param_get(params, "hazardCertReady", "hazard_cert_ready"),
|
||||
hazard_cert_ready_in=_param_get(
|
||||
@@ -431,6 +434,12 @@ def list_plans(
|
||||
license_plate: Optional[str] = Query(default=None, alias="licensePlate", description="车牌号"),
|
||||
plan_date_from: Optional[date] = Query(default=None, alias="planDateFrom", description="计划日期开始"),
|
||||
plan_date_to: Optional[date] = Query(default=None, alias="planDateTo", description="计划日期结束"),
|
||||
delivery_time_from: Optional[date] = Query(
|
||||
default=None, alias="deliveryTimeFrom", description="送货时间开始"
|
||||
),
|
||||
delivery_time_to: Optional[date] = Query(
|
||||
default=None, alias="deliveryTimeTo", description="送货时间结束"
|
||||
),
|
||||
has_hazard_product: Optional[int] = Query(
|
||||
default=None,
|
||||
alias="hasHazardProduct",
|
||||
@@ -505,6 +514,8 @@ def list_plans(
|
||||
licensePlate=license_plate,
|
||||
planDateFrom=plan_date_from,
|
||||
planDateTo=plan_date_to,
|
||||
deliveryTimeFrom=delivery_time_from,
|
||||
deliveryTimeTo=delivery_time_to,
|
||||
certUploadStatus=cert_upload_status,
|
||||
hazardCertReady=hazard_cert_ready,
|
||||
)
|
||||
@@ -633,6 +644,7 @@ PLAN_EXPORT_COLUMNS = [
|
||||
ExportColumn(title="计划编号", field="planNo"),
|
||||
ExportColumn(title="跟进状态", field="followStatus"),
|
||||
ExportColumn(title="计划日期", field="planDate"),
|
||||
ExportColumn(title="送货时间", field="deliveryTimes"),
|
||||
ExportColumn(title="单据类型", field="planType"),
|
||||
ExportColumn(title="供方", field="supplierName"),
|
||||
ExportColumn(title="需方", field="customerName"),
|
||||
@@ -703,6 +715,8 @@ class PlanExportBody(BaseModel):
|
||||
license_plate: Optional[str] = Field(default=None, alias="licensePlate")
|
||||
plan_date_from: Optional[date] = Field(default=None, alias="planDateFrom")
|
||||
plan_date_to: Optional[date] = Field(default=None, alias="planDateTo")
|
||||
delivery_time_from: Optional[date] = Field(default=None, alias="deliveryTimeFrom")
|
||||
delivery_time_to: Optional[date] = Field(default=None, alias="deliveryTimeTo")
|
||||
has_hazard_product: Optional[int] = Field(default=None, alias="hasHazardProduct")
|
||||
cert_upload_status: Optional[str] = Field(default=None, alias="certUploadStatus")
|
||||
hazard_cert_ready: Optional[int] = Field(default=None, alias="hazardCertReady")
|
||||
@@ -771,6 +785,8 @@ def export_plans(
|
||||
sheet_title = "计划归档"
|
||||
filename_stem = f"计划归档_{date_str}"
|
||||
else:
|
||||
plan_ids = [plan.id for plan in plans]
|
||||
stops_by_plan = load_plan_stops_grouped(db, tenant_no, plan_ids)
|
||||
items = []
|
||||
for plan in plans:
|
||||
data = PlanWithProducts.model_validate(plan).model_dump(by_alias=True)
|
||||
@@ -778,6 +794,9 @@ def export_plans(
|
||||
data["planDate"] = str(data["planDate"])[:10]
|
||||
if data.get("erpEntered") is not None:
|
||||
data["erpEntered"] = "是" if int(data["erpEntered"]) else "否"
|
||||
_load_read, delivery_reads = stops_by_plan.get(plan.id, (None, []))
|
||||
times = collect_unique_delivery_date_strings(delivery_reads)
|
||||
data["deliveryTimes"] = " / ".join(times) if times else ""
|
||||
items.append(data)
|
||||
cols = filter_export_columns(PLAN_EXPORT_COLUMNS, body.columns)
|
||||
sheet_title = "计划列表"
|
||||
@@ -884,6 +903,8 @@ def list_contract_gaps(
|
||||
),
|
||||
plan_date_from: Optional[date] = Query(default=None, alias="planDateFrom"),
|
||||
plan_date_to: Optional[date] = Query(default=None, alias="planDateTo"),
|
||||
delivery_time_from: Optional[date] = Query(default=None, alias="deliveryTimeFrom"),
|
||||
delivery_time_to: Optional[date] = Query(default=None, alias="deliveryTimeTo"),
|
||||
plan_type: Optional[str] = Query(default=None, alias="planType"),
|
||||
follow_status: Optional[str] = Query(default=None, alias="followStatus"),
|
||||
q: Optional[str] = Query(
|
||||
@@ -901,6 +922,8 @@ def list_contract_gaps(
|
||||
customerKeyword=customer_keyword,
|
||||
planDateFrom=plan_date_from,
|
||||
planDateTo=plan_date_to,
|
||||
deliveryTimeFrom=delivery_time_from,
|
||||
deliveryTimeTo=delivery_time_to,
|
||||
planType=plan_type,
|
||||
followStatus=follow_status,
|
||||
)
|
||||
@@ -915,6 +938,8 @@ def list_contract_gaps(
|
||||
customer_keyword=_param_get(params, "customerKeyword", "customer_keyword"),
|
||||
plan_date_from=_param_get(params, "planDateFrom", "plan_date_from"),
|
||||
plan_date_to=_param_get(params, "planDateTo", "plan_date_to"),
|
||||
delivery_time_from=_param_get(params, "deliveryTimeFrom", "delivery_time_from"),
|
||||
delivery_time_to=_param_get(params, "deliveryTimeTo", "delivery_time_to"),
|
||||
plan_type=_param_get(params, "planType", "plan_type"),
|
||||
plan_type_in=_param_get(params, "planTypeIn", "plan_type_in"),
|
||||
follow_status=_param_get(params, "followStatus", "followStatusIn", "follow_status"),
|
||||
@@ -929,6 +954,7 @@ def list_contract_gaps(
|
||||
CONTRACT_GAP_EXPORT_COLUMNS = [
|
||||
ExportColumn(title="计划编号", field="planNo"),
|
||||
ExportColumn(title="计划日期", field="planDate"),
|
||||
ExportColumn(title="送货时间", field="deliveryTimes"),
|
||||
ExportColumn(title="单据类型", field="planType"),
|
||||
ExportColumn(title="跟进状态", field="followStatus"),
|
||||
ExportColumn(title="供方", field="supplierName"),
|
||||
@@ -943,6 +969,8 @@ class ContractGapExportBody(BaseModel):
|
||||
customer_keyword: Optional[str] = Field(default=None, alias="customerKeyword")
|
||||
plan_date_from: Optional[date] = Field(default=None, alias="planDateFrom")
|
||||
plan_date_to: Optional[date] = Field(default=None, alias="planDateTo")
|
||||
delivery_time_from: Optional[date] = Field(default=None, alias="deliveryTimeFrom")
|
||||
delivery_time_to: Optional[date] = Field(default=None, alias="deliveryTimeTo")
|
||||
q: Optional[str] = None
|
||||
ids: Optional[List[str]] = None
|
||||
columns: Optional[List[str]] = None
|
||||
@@ -969,6 +997,12 @@ def export_contract_gaps(
|
||||
customer_keyword=_param_get(params, "customerKeyword", "customer_keyword"),
|
||||
plan_date_from=_param_get(params, "planDateFrom", "plan_date_from"),
|
||||
plan_date_to=_param_get(params, "planDateTo", "plan_date_to"),
|
||||
delivery_time_from=_param_get(
|
||||
params, "deliveryTimeFrom", "delivery_time_from"
|
||||
),
|
||||
delivery_time_to=_param_get(
|
||||
params, "deliveryTimeTo", "delivery_time_to"
|
||||
),
|
||||
plan_type=_param_get(params, "planType", "plan_type"),
|
||||
plan_type_in=_param_get(params, "planTypeIn", "plan_type_in"),
|
||||
follow_status=_param_get(
|
||||
@@ -995,6 +1029,9 @@ def export_contract_gaps(
|
||||
data["gapType"] = "仅缺需方合同"
|
||||
else:
|
||||
data["gapType"] = ""
|
||||
times = data.get("deliveryTimes") or []
|
||||
if isinstance(times, list):
|
||||
data["deliveryTimes"] = " / ".join(str(t) for t in times) if times else ""
|
||||
for k, v in list(data.items()):
|
||||
if hasattr(v, "isoformat"):
|
||||
data[k] = str(v)[:19]
|
||||
|
||||
@@ -22,8 +22,11 @@ from app.schemas.pl.plan import (
|
||||
PlanLoadRead,
|
||||
PlanProductRead,
|
||||
)
|
||||
from app.services.pl.plan_list_filters import build_plan_column_filters
|
||||
from app.services.pl_plan_stop_service import collect_unique_delivery_date_strings
|
||||
from app.services.pl.plan_list_filters import (
|
||||
_parse_date,
|
||||
build_plan_column_filters,
|
||||
plan_delivery_time_exists,
|
||||
)
|
||||
from app.services.pl_data_scope import apply_pl_scope
|
||||
from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES, is_internal_customer_name
|
||||
from app.services.pl_plan_service import (
|
||||
@@ -38,6 +41,7 @@ from app.services.pl_plan_stop_service import (
|
||||
PLAN_CONTRACT_SIDE_DELIVERY,
|
||||
PLAN_CONTRACT_SIDE_LOAD,
|
||||
assert_at_most_one_contract,
|
||||
collect_unique_delivery_date_strings,
|
||||
load_plan_stops_grouped,
|
||||
)
|
||||
from app.services.pl_product_display import load_crm_product_alias_maps, resolve_product_display_names
|
||||
@@ -330,6 +334,8 @@ def list_plan_contract_gaps(
|
||||
customer_keyword: Optional[str] = None,
|
||||
plan_date_from: Optional[date] = None,
|
||||
plan_date_to: Optional[date] = None,
|
||||
delivery_time_from: Optional[date] = None,
|
||||
delivery_time_to: Optional[date] = None,
|
||||
plan_type: Optional[str] = None,
|
||||
plan_type_in: Optional[str] = None,
|
||||
follow_status: Optional[str] = None,
|
||||
@@ -419,6 +425,13 @@ def list_plan_contract_gaps(
|
||||
if column_filters:
|
||||
query = query.filter(*column_filters)
|
||||
|
||||
dt_from = _parse_date(delivery_time_from)
|
||||
dt_to = _parse_date(delivery_time_to)
|
||||
if dt_from is not None or dt_to is not None:
|
||||
query = query.filter(
|
||||
plan_delivery_time_exists(db, tenant_no, d_from=dt_from, d_to=dt_to)
|
||||
)
|
||||
|
||||
if q:
|
||||
q_kw = q.strip()
|
||||
if q_kw:
|
||||
|
||||
Reference in new issue
Block a user