Преглед на файлове

Stock Lot Ledger UI fix

fix負數倉
Harry Groves преди 11 часа
родител
ревизия
0157ce4b46
променени са 4 файла, в които са добавени 98 реда и са изтрити 4 реда
  1. +86
    -0
      src/app/(main)/report/page.tsx
  2. +10
    -2
      src/config/reportConfig.ts
  3. +1
    -1
      src/i18n/en/report.json
  4. +1
    -1
      src/i18n/zh/report.json

+ 86
- 0
src/app/(main)/report/page.tsx Целия файл

@@ -57,6 +57,21 @@ interface ItemCodeWithName {
name: string;
}

/** Months from the earliest ledger month through the current month. Value stays YYYY-MM-01. */
function ledgerMonthOptions(isZh: boolean, earliest: string) {
const start = dayjs().startOf('month');
let end = dayjs(earliest).startOf('month');
if (!end.isValid() || end.isAfter(start)) end = start;
const count = start.diff(end, 'month') + 1;
return Array.from({ length: count }, (_, i) => {
const d = start.subtract(i, 'month');
return {
value: d.format(OUTPUT_DATE_FORMAT),
label: isZh ? `${d.year()}年${d.month() + 1}月` : d.format('MMMM YYYY'),
};
});
}

const FIELD_ERROR_SX = {
'& .MuiOutlinedInput-root.Mui-error': {
'& .MuiOutlinedInput-notchedOutline': {
@@ -97,6 +112,7 @@ export default function ReportPage() {
session?.abilities?.includes(AUTH.ADMIN) ?? false;

const [selectedReportId, setSelectedReportId] = useState<string>('');
const [ledgerEarliest, setLedgerEarliest] = useState<{ reportId: string; earliest: string } | null>(null);
const [criteria, setCriteria] = useState<Record<string, string>>({});
const criteriaRef = useRef<Record<string, string>>({});
const pendingItemCodeInputRef = useRef<Record<string, string>>({});
@@ -269,6 +285,32 @@ export default function ReportPage() {
}
};

// Earliest stock_ledger month for the period-start list. Newest month is always the current month.
useEffect(() => {
const endpoint = currentReport?.fields.find(
(field) => field.type === 'month' && field.earliestMonthEndpoint,
)?.earliestMonthEndpoint;
if (!currentReport || !endpoint) return;
const reportId = currentReport.id;
let cancelled = false;
(async () => {
try {
const response = await clientAuthFetch(endpoint);
if (!response.ok) return;
const data = await response.json();
const earliest = typeof data?.earliest === 'string' ? data.earliest : '';
if (!cancelled && earliest) {
setLedgerEarliest({ reportId, earliest });
}
} catch (error) {
console.error('Failed to load ledger months', error);
}
})();
return () => {
cancelled = true;
};
}, [currentReport]);

// Load initial options when report is selected
useEffect(() => {
if (currentReport) {
@@ -661,6 +703,50 @@ export default function ReportPage() {
field.name === 'status' &&
rep012MultiRound;

if (field.type === 'month') {
const earliestForReport =
ledgerEarliest?.reportId === currentReport.id ? ledgerEarliest.earliest : '';
const monthOptions = earliestForReport
? ledgerMonthOptions(isZh, earliestForReport)
: [];
return (
<Grid item {...gridSize} key={fieldKey}>
<TextField
select
fullWidth
required={field.required}
error={Boolean(fieldErrors[field.name])}
helperText={fieldErrors[field.name] || undefined}
label={translatedLabel}
value={currentValue}
disabled={disabledByCheckedCheckbox || disabledRep012Status || !!field.disabled}
onChange={(e) => handleFieldChange(field.name, e.target.value)}
sx={{
...FIELD_ERROR_SX,
...(currentReport.id === 'rep-005' ? {
'& .MuiOutlinedInput-root': {
minHeight: '64px',
fontSize: '1rem'
},
'& .MuiInputLabel-root': {
fontSize: '1rem'
}
} : {}),
}}
>
<MenuItem value="" disabled>
{isZh ? '請選擇月份' : 'Select month'}
</MenuItem>
{monthOptions.map((opt) => (
<MenuItem key={opt.value} value={opt.value}>
{opt.label}
</MenuItem>
))}
</TextField>
</Grid>
);
}

if (field.type === 'date') {
const parsed = currentValue ? dayjs(currentValue) : null;
const dateError = fieldErrors[field.name];


+ 10
- 2
src/config/reportConfig.ts Целия файл

@@ -1,5 +1,5 @@
/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */
export type FieldType = 'date' | 'text' | 'select' | 'number' | 'checkbox';
export type FieldType = 'date' | 'month' | 'text' | 'select' | 'number' | 'checkbox';

import { NEXT_PUBLIC_API_URL } from "@/config/api";

@@ -29,6 +29,8 @@ export interface ReportField {
multiline?: boolean;
/** Rows for multiline text areas. Default 4. */
minRows?: number;
/** Month fields: GET returning { earliest: "YYYY-MM-DD" }. List runs from that month through the current month. */
earliestMonthEndpoint?: string;
}

export type ReportResponseType = 'pdf' | 'excel';
@@ -322,7 +324,13 @@ export const REPORTS: ReportDefinition[] = [
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-lot-ledger`,
responseType: "excel",
fields: [
{ label: "期間起 Period From(永遠該月1日)", name: "lastInDateStart", type: "date", required: true },
{
label: "期間起 Period From",
name: "lastInDateStart",
type: "month",
required: true,
earliestMonthEndpoint: `${NEXT_PUBLIC_API_URL}/report/stock-lot-ledger-earliest`,
},
{ label: "期間迄 Period To", name: "lastInDateEnd", type: "date", required: true },
asyncItemCodeField(),
],


+ 1
- 1
src/i18n/en/report.json Целия файл

@@ -139,7 +139,7 @@
"rep-020": {
"title": "Stock Lot Ledger Report",
"fields": {
"lastInDateStart": "Period From (always 1st of month)",
"lastInDateStart": "Period From",
"lastInDateEnd": "Period To",
"itemCode": "Item Code"
}


+ 1
- 1
src/i18n/zh/report.json Целия файл

@@ -139,7 +139,7 @@
"rep-020": {
"title": "庫存流水帳報告",
"fields": {
"lastInDateStart": "期間起(永遠該月1日)",
"lastInDateStart": "期間起",
"lastInDateEnd": "期間迄",
"itemCode": "貨品編號"
}


Зареждане…
Отказ
Запис