优化付款交货待办展示并支持列表快捷登记

This commit is contained in:
reddaniel110
2026-09-17 15:20:39 +08:00
parent 000f4198a8
commit 0e45a58e5b
16 changed files with 591 additions and 103 deletions
+69 -7
View File
@@ -1,8 +1,8 @@
"""Internal order follow-up; approved documents stay frozen."""
from datetime import date
from flask import abort, flash, redirect, request, url_for
from sqlalchemy import and_, or_
from flask import abort, flash, jsonify, redirect, render_template, request, url_for
from sqlalchemy import and_, case, or_
from models import DELIVERY_STATUS, INVOICE_STATUS, PAYMENT_STATUS, Order
from order_logic import add_log, get_order, normalize_date
@@ -10,6 +10,7 @@ from security import current_user, db, login_required
TRACKING_FILTERS = {
'open': '待跟进订单',
'prepayment': '需预付款',
'invoice_due': '已收票待付款',
'unpaid': '未付款',
@@ -22,6 +23,7 @@ TRACKING_FILTERS = {
'completed': '已付款且已交货',
'unrecorded': '跟进待登记',
'recheck': '变更后待核对',
'closed': '付款、交货、收票均完成',
}
@@ -30,7 +32,12 @@ def tracking_conditions():
current_payment = or_(Order.payment_revision < 0, Order.payment_revision == Order.revision)
payment_due = and_(current_payment, Order.payment_status.in_(('unpaid', 'partial')))
delivery_open = and_(current_fulfillment, Order.delivery_status.in_(('pending', 'partial')))
completed = and_(current_payment, current_fulfillment, Order.payment_status == 'paid',
Order.delivery_status == 'delivered')
closed = and_(completed, Order.invoice_status == 'received')
return {
'open': ~closed,
'closed': closed,
'prepayment': and_(current_fulfillment, Order.needs_prepayment.is_(True), payment_due),
'invoice_due': and_(current_fulfillment, Order.invoice_status == 'received', payment_due),
'unpaid': and_(current_payment, Order.payment_status == 'unpaid'),
@@ -40,8 +47,7 @@ def tracking_conditions():
'partial_delivery': and_(current_fulfillment, Order.delivery_status == 'partial'),
'delivered': and_(current_fulfillment, Order.delivery_status == 'delivered'),
'paid_undelivered': and_(current_payment, Order.payment_status == 'paid', delivery_open),
'completed': and_(current_payment, current_fulfillment, Order.payment_status == 'paid',
Order.delivery_status == 'delivered'),
'completed': completed,
'unrecorded': or_(Order.invoice_status == 'unknown', Order.delivery_status == 'unknown',
Order.payment_status == 'unknown'),
'recheck': or_(~current_fulfillment, ~current_payment),
@@ -57,6 +63,48 @@ def filter_tracking(query, key):
return query.filter(Order.status == 'approved', conditions[key])
def tracking_priority():
conditions = tracking_conditions()
return case(*[(conditions[key], rank) for rank, key in enumerate(
('recheck', 'prepayment', 'invoice_due', 'paid_undelivered', 'unrecorded'))], else_=5)
def tracking_tasks(order):
if order.status != 'approved':
return []
if order.fulfillment_stale or order.payment_stale:
return [('recheck', '变更后待核对')]
tasks = []
if order.payment_status in ('unpaid', 'partial'):
if order.needs_prepayment:
tasks.append(('prepayment', '安排预付款' if order.payment_status == 'unpaid' else '核对预付款及剩余付款安排'))
elif order.invoice_status == 'received':
tasks.append(('invoice_due', '已收票,跟进付款' if order.payment_status == 'unpaid' else '跟进剩余付款'))
else:
tasks.append(('payment', '跟进付款安排'))
if order.delivery_status in ('pending', 'partial'):
tasks.append(('delivery', '跟进剩余交货' if order.delivery_status == 'partial' else '跟进交货'))
if order.invoice_status == 'pending':
tasks.append(('invoice', '跟进收票'))
if 'unknown' in (order.payment_status, order.delivery_status, order.invoice_status):
tasks.append(('unrecorded', '补充跟进登记'))
return tasks or [('closed', '付款、交货、收票均完成')]
def latest_tracking(order):
latest = {}
for log in reversed(order.logs):
if log.action in ('更新采购跟进', '登记付款状态') and log.action not in latest:
latest[log.action] = log
return latest
def tracking_response(oid):
if request.headers.get('X-Tracking-Modal') == '1':
return jsonify(ok=True)
return redirect(url_for('order_view', oid=oid) + '#order-tracking')
def can_follow(order, user):
return (order.status == 'approved' and user.role in ('maker', 'admin')
and (user.role == 'admin' or order.created_by == user.id))
@@ -84,7 +132,21 @@ def register_tracking_routes(app):
@app.context_processor
def tracking_context():
return {'INVOICE_STATUS': INVOICE_STATUS, 'DELIVERY_STATUS': DELIVERY_STATUS,
'PAYMENT_STATUS': PAYMENT_STATUS, 'TRACKING_FILTERS': TRACKING_FILTERS}
'PAYMENT_STATUS': PAYMENT_STATUS, 'TRACKING_FILTERS': TRACKING_FILTERS,
'can_follow': can_follow, 'can_record_payment': can_record_payment,
'tracking_tasks': tracking_tasks, 'latest_tracking': latest_tracking}
@app.get('/orders/<int:oid>/tracking/<kind>')
@login_required
def tracking_editor(oid, kind):
if kind not in ('follow-up', 'payment'):
abort(404)
order, user = get_order(oid), current_user()
allowed = can_follow(order, user) if kind == 'follow-up' else can_record_payment(order, user)
if not allowed:
abort(403)
template = 'tracking_editor_fragment.html' if request.args.get('fragment') == '1' else 'tracking_editor.html'
return render_template(template, o=order, user=user, kind=kind)
@app.post('/orders/<int:oid>/follow-up')
@login_required
@@ -124,7 +186,7 @@ def register_tracking_routes(app):
add_log(order, '更新采购跟进', user, ';'.join(changes + (['更正原因:' + reason] if reason else [])))
db.commit()
flash('采购跟进已保存', 'ok')
return redirect(url_for('order_view', oid=oid) + '#order-tracking')
return tracking_response(oid)
@app.post('/orders/<int:oid>/payment')
@login_required
@@ -160,4 +222,4 @@ def register_tracking_routes(app):
add_log(order, '登记付款状态', user, ';'.join(changes + (['更正原因:' + reason] if reason else [])))
db.commit()
flash('付款状态已保存', 'ok')
return redirect(url_for('order_view', oid=oid) + '#order-tracking')
return tracking_response(oid)