feat(frontend): unified warehouse UI, calendar fix, partial receipts, RBAC views, admin panel, dev-mode 3-step
- header: icon box + dynamic subheader '[user] | [role] – [project/همه پروژهها]' on every warehouse page; module context kept in the hamburger (items 1-2) - project manager view: office button + inline logout removed; hamburger contains only «خروج از حساب»; sub-views get «بازگشت به داشبورد» (Header backTo/goBack); «افزایش موجود» primary button on the dashboard (item 8) - daily control: cells render the day-of-month (was the Jalali year), month nav uses real Jalali months, header is pure Jalali «امروز ۸ شهریور ۱۴۰۵», today gets a blue accent (item 3) - arrivals: partial (item/qty) receipt — any valid item is enough to submit, ceiling + allocation-sum validation with inline errors, Received/In-Transit badges; ledger shows «رسیده X از Y» / «در راه Z» + «رسید جزیی» badge (item 4) - api client: multipart uploads no longer send Content-Type json (fixes the invoice/proforma 400 «دادهی ارسالشده نامعتبر است»); undefined query params are dropped (fixes empty admin project filter, item 5) - organization: user-creation card removed, role column read-only for procurement manager, Casdoor sync button (item 6) - admin panel (/admin): Casdoor user sync + grant/revoke «مدیر تدارکات»; Developer Mode is a 3-step admin-gated flow on the login page (item 7)
This commit is contained in:
@@ -61,19 +61,24 @@ export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit
|
||||
}
|
||||
|
||||
// ستون رسید — v2.6: تأیید رسید فقط در «پنل مدیریت انبار» توسط مدیر پروژه انجام میشود؛
|
||||
// اینجا فقط وضعیت نمایش داده میشود.
|
||||
// اینجا فقط وضعیت نمایش داده میشود. با رسید جزیی: «رسیده X از Y» + «در راه Z».
|
||||
const activeItems = (q.line_items || []).filter((li) => !li.rejected);
|
||||
const receivedSum = activeItems.reduce((s, li) => s + (li.received_qty || 0), 0);
|
||||
const orderedSum = activeItems.reduce((s, li) => s + (li.quantity || 0), 0);
|
||||
const partiallyReceived = q.status === "accepted" && receivedSum > 0 && receivedSum < orderedSum;
|
||||
|
||||
let arrivedCell: React.ReactNode;
|
||||
if (q.status === "accepted") {
|
||||
if (q.arrived_date) {
|
||||
arrivedCell = <span className="tabular-nums">{fmtDateTime(q.arrived_date)}</span>;
|
||||
} else {
|
||||
const items = (q.line_items || []).filter((li) => !li.rejected);
|
||||
const arrivedCount = items.filter((li) => li.arrived_date).length;
|
||||
arrivedCell = arrivedCount ? (
|
||||
<span className="tabular-nums">{fmtNum(arrivedCount)}/{fmtNum(items.length)}</span>
|
||||
) : (
|
||||
<span className="text-muted">در انتظار PM</span>
|
||||
} else if (receivedSum > 0) {
|
||||
arrivedCell = (
|
||||
<span className="tabular-nums">
|
||||
رسیده {fmtNum(receivedSum)} از {fmtNum(orderedSum)} — در راه {fmtNum(Math.max(0, orderedSum - receivedSum))}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
arrivedCell = <span className="text-muted">در انتظار PM</span>;
|
||||
}
|
||||
} else if (q.arrived_date) {
|
||||
arrivedCell = <span className="tabular-nums">{fmtDateTime(q.arrived_date)}</span>;
|
||||
@@ -105,6 +110,7 @@ export function QuoteCard({ store, q, expanded, onToggleExpand, onAccept, onEdit
|
||||
</div>
|
||||
<div className="ms-auto flex shrink-0 items-center gap-1.5">
|
||||
<Badge variant={q.status as "offered" | "accepted" | "arrived"}>{STATUS_LABEL[q.status]}</Badge>
|
||||
{partiallyReceived && <Badge variant="offered">رسید جزیی</Badge>}
|
||||
<button className="chip" onClick={onEdit} title="ویرایش پیشنهاد">
|
||||
<Pencil className="h-3 w-3" />
|
||||
ویرایش
|
||||
|
||||
Reference in New Issue
Block a user