add day-end and change item model

This commit is contained in:
Dhananjaya99
2026-08-20 14:10:39 +05:30
parent 8835ba9500
commit 4cc6a546c7
43 changed files with 8955 additions and 1680 deletions
+36 -1
View File
@@ -47,7 +47,36 @@ export function readCsrfToken(): string | null {
return match ? decodeURIComponent(match[1]) : null
}
async function rawRequest(path: string, options: RequestOptions = {}): Promise<Response> {
// erp_at is short-lived; erp_rt (a separate, refresh-route-scoped cookie) outlives it. Before
// this, an expired erp_at surfaced as a bare 401 on whatever the user happened to click next
// (confirming an invoice, recording a payment, ...) with no attempt to renew the session — this
// dedupes concurrent 401s onto one /auth/refresh-token call so every caller gets one retry.
let refreshPromise: Promise<boolean> | null = null
function refreshSession(): Promise<boolean> {
if (!refreshPromise) {
refreshPromise = fetch(`${API_BASE}/auth/refresh-token`, {
method: "POST",
credentials: "include",
headers: { Accept: "application/json", "Content-Type": "application/json" },
body: "{}",
})
.then((res) => res.ok)
.catch(() => false)
.finally(() => {
refreshPromise = null
})
}
return refreshPromise
}
function redirectToLogin() {
if (typeof window === "undefined") return
const next = `${window.location.pathname}${window.location.search}`
window.location.href = `/login?next=${encodeURIComponent(next)}`
}
async function rawRequest(path: string, options: RequestOptions = {}, isRetry = false): Promise<Response> {
const { body, ifMatch, idempotencyKey, csrf, headers, ...rest } = options
const csrfToken = csrf ? readCsrfToken() : null
// Multipart uploads (attendance files, staff documents) pass a FormData body — the
@@ -70,6 +99,12 @@ async function rawRequest(path: string, options: RequestOptions = {}): Promise<R
body: isFormData ? (body as FormData) : body !== undefined ? JSON.stringify(body) : undefined,
})
if (response.status === 401 && !isRetry && !path.startsWith("/auth/")) {
const refreshed = await refreshSession()
if (refreshed) return rawRequest(path, options, true)
redirectToLogin()
}
if (!response.ok) {
let problem: ProblemDetails
try {
+5
View File
@@ -7,6 +7,7 @@ import {
BundleSaleTemplate,
BundleSaleTemplateSummary,
CreateBundleSaleRequest,
CreateBundleSaleTemplateRequest,
UpdateBundleSaleRequest,
} from "@/types/bundles"
@@ -46,4 +47,8 @@ export const bundleApi = {
getTemplate(bundleSaleTemplateId: number): Promise<BundleSaleTemplate> {
return apiRequest<BundleSaleTemplate>(`/bundle-sales/templates/${bundleSaleTemplateId}`)
},
createTemplate(request: CreateBundleSaleTemplateRequest): Promise<BundleSaleTemplate> {
return apiRequest<BundleSaleTemplate>("/bundle-sales/templates", { method: "POST", body: request })
},
}
+2 -2
View File
@@ -2,5 +2,5 @@ import { ItemListItem } from "@/types/master-data"
export function getSuggestedUnitPrice(items: ItemListItem[], itemId: number | null | undefined): number | null {
if (!itemId) return null
return items.find((item) => item.itemId === itemId)?.salePrice ?? null
}
return items.find((item) => item.itemId === itemId)?.sellingFlatPrice ?? null
}