diff --git a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-items-dialog.tsx b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-items-dialog.tsx index 5b1b20a..d3d80e1 100644 --- a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-items-dialog.tsx +++ b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-items-dialog.tsx @@ -19,6 +19,8 @@ import { import { Checkbox } from '@/components/ui/checkbox' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' +import { HugeiconsIcon } from '@hugeicons/react' +import { ViewIcon } from '@hugeicons/core-free-icons' import { toast } from '@/components/ui/toast' import { shopPos as shopPosApi, @@ -45,7 +47,9 @@ interface PickedLine { shopPOItemId: string itemId: string itemName: string + storeId: string storeName: string + shopPOId: string orderedQty: number remainingQty: number checked: boolean @@ -60,6 +64,8 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa const [regionId, setRegionId] = useState('') const [routeId, setRouteId] = useState('') const [warehouseId, setWarehouseId] = useState('') + const [shopId, setShopId] = useState('') + const [viewStoreId, setViewStoreId] = useState('') const [pos, setPos] = useState([]) const [loading, setLoading] = useState(false) @@ -71,6 +77,8 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa setRegionId('') setRouteId('') setWarehouseId('') + setShopId('') + setViewStoreId('') setPos([]) setLines({}) @@ -88,6 +96,7 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa useEffect(() => { if (!open) return setRouteId('') + setShopId('') setPos([]) setLines({}) routesApi.list({ regionId: regionId || undefined, pageSize: 200 }) @@ -98,6 +107,8 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa useEffect(() => { if (!open) return setLines({}) + setShopId('') + setViewStoreId('') if (!routeId) { setPos([]) return @@ -123,7 +134,9 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa shopPOItemId: item.id, itemId: item.itemId, itemName: item.itemName, + storeId: po.storeId, storeName: po.storeName, + shopPOId: po.id, orderedQty: item.quantity, remainingQty: remaining, checked: false, @@ -135,6 +148,39 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa return result }, [pos, lines]) + const allShopGroups = useMemo(() => { + const map = new Map; rows: PickedLine[] }>() + for (const row of rows) { + const g = map.get(row.storeId) ?? { storeId: row.storeId, storeName: row.storeName, poIds: new Set(), rows: [] } + g.rows.push(row) + g.poIds.add(row.shopPOId) + map.set(row.storeId, g) + } + return Array.from(map.values()).sort((a, b) => a.storeName.localeCompare(b.storeName)) + }, [rows]) + + const shopGroups = useMemo( + () => (shopId ? allShopGroups.filter((g) => g.storeId === shopId) : allShopGroups), + [allShopGroups, shopId] + ) + + const viewGroup = allShopGroups.find((g) => g.storeId === viewStoreId) + + const summary = useMemo(() => { + const map = new Map }>() + for (const row of rows) { + const line = lines[row.shopPOItemId] ?? row + if (!line.checked || !(line.quantity > 0)) continue + const e = map.get(row.itemId) ?? { itemName: row.itemName, qty: 0, shops: new Set() } + e.qty += line.quantity + e.shops.add(row.storeId) + map.set(row.itemId, e) + } + return Array.from(map.values()).sort((a, b) => a.itemName.localeCompare(b.itemName)) + }, [rows, lines]) + + const summaryTotal = summary.reduce((s, e) => s + e.qty, 0) + function toggleLine(line: PickedLine, checked: boolean) { setLines((prev) => ({ ...prev, [line.shopPOItemId]: { ...line, checked } })) } @@ -153,7 +199,7 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa toast.add({ title: 'Select a warehouse first', type: 'error' }) return } - const selected = rows.filter((r) => (lines[r.shopPOItemId]?.checked ?? false)) + const selected = rows.filter((r) => (lines[r.shopPOItemId]?.checked ?? false) && lines[r.shopPOItemId].quantity > 0) if (selected.length === 0) { toast.add({ title: 'Select at least one item', type: 'error' }) return @@ -171,8 +217,25 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa setSubmitting(true) try { - await loadingSheetsApi.updateItems(sheet.id, items) - toast.add({ title: 'Loading sheet items saved', type: 'success' }) + let target = sheet + if (sheet.status === 'Confirmed') { + // A confirmed sheet is locked (stock already moved), so extra items go on a + // follow-up Planned sheet for the same ride. + const existing = getPaginatedItems( + await loadingSheetsApi.list({ rideId: sheet.fK_RideId, status: 'Planned', pageSize: 1 }) + )[0] + target = existing ?? await loadingSheetsApi.create({ + fK_RideId: sheet.fK_RideId, + populatedByUserId: sheet.populatedBy, + }) + } + await loadingSheetsApi.updateItems(target.id, items) + toast.add({ + title: sheet.status === 'Confirmed' + ? 'Items saved on a new planned loading sheet — confirm it to load them' + : 'Loading sheet items saved', + type: 'success', + }) onSuccess() onClose() } catch (err) { @@ -192,6 +255,9 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa Select a route first. Confirmed Shop POs for that route will then be available to pick items from. + {sheet.status === 'Confirmed' && ( + <> This sheet is already confirmed, so the items you pick are saved on a new planned sheet for the same ride. + )} @@ -225,6 +291,21 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa +
+ + +
+
setLineQuantity(row, Number(e.target.value))} - /> - - - ) - }) - )} - - +
+ {!routeId ? ( +

Select a route to see shops with confirmed POs.

+ ) : loading ? ( +

Loading…

+ ) : shopGroups.length === 0 ? ( +

No shops with confirmed POs found for this selection.

+ ) : ( + shopGroups.map((group) => { + const groupLines = group.rows.map((r) => lines[r.shopPOItemId] ?? r) + const allChecked = groupLines.every((l) => l.checked) + const someChecked = groupLines.some((l) => l.checked) + return ( +
+ group.rows.forEach((r) => toggleLine(lines[r.shopPOItemId] ?? r, v === true))} + /> + {group.storeName} + + {group.poIds.size} PO{group.poIds.size === 1 ? '' : 's'} + + +
+ ) + }) + )} +
+ +
+
+ Loading Sheet Summary + {summary.length} item{summary.length === 1 ? '' : 's'} · {summaryTotal} units +
+ {summary.length === 0 ? ( +

Tick items above to build the summary.

+ ) : ( + + + {summary.map((e) => ( + + + + + + ))} + +
{e.itemName}{e.shops.size} shop{e.shops.size === 1 ? '' : 's'}{e.qty}
+ )}
@@ -298,6 +389,61 @@ export function LoadingSheetItemsDialog({ open, onClose, onSuccess, sheet }: Loa {submitting ? 'Saving…' : 'Save Items'} + + !v && setViewStoreId('')}> + + + {viewGroup?.storeName} + + Confirmed PO items. Tick the items to load and set the quantity. + + +
+ + + + + + + + + + + + {viewGroup?.rows.map((row) => { + const line = lines[row.shopPOItemId] ?? row + return ( + + + + + + + + ) + })} + +
ItemPOOrderedQty to load
+ toggleLine(row, v === true)} + /> + {row.itemName}{row.shopPOId.substring(0, 8)}{row.remainingQty} + setLineQuantity(row, Number(e.target.value))} + /> +
+
+ + + +
+
) diff --git a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-view-sheet.tsx b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-view-sheet.tsx index 227f6ad..7b787f4 100644 --- a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-view-sheet.tsx +++ b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheet-view-sheet.tsx @@ -1,5 +1,6 @@ 'use client' +import { useMemo } from 'react' import { Badge } from '@/components/ui/badge' import { Dialog, @@ -8,7 +9,11 @@ import { DialogTitle, } from '@/components/ui/dialog' import { Separator } from '@/components/ui/separator' -import type { LoadingSheetResponse, LoadingSheetStatus } from '@/types/api' +import type { + LoadingSheetItemResponse, + LoadingSheetResponse, + LoadingSheetStatus, +} from '@/types/api' const LS_STATUS_VARIANT: Record = { Planned: 'secondary', @@ -24,6 +29,35 @@ const fmtDateTime = (v: string | null) => const truncId = (id: string) => id.substring(0, 8) +const UNASSIGNED = '__unassigned__' + +interface SummaryRow { + itemId: string + itemName: string + total: number + shops: number + warehouses: { name: string; qty: number }[] +} + +function buildSummary(items: LoadingSheetItemResponse[]): SummaryRow[] { + const map = new Map }>() + for (const item of items) { + let row = map.get(item.fK_ItemId) + if (!row) { + row = { itemId: item.fK_ItemId, itemName: item.itemName, total: 0, shops: 0, warehouses: [], shopSet: new Set() } + map.set(item.fK_ItemId, row) + } + row.total += item.quantityDispatched + row.shopSet.add(item.storeId ?? UNASSIGNED) + const wh = row.warehouses.find((w) => w.name === item.warehouseName) + if (wh) wh.qty += item.quantityDispatched + else row.warehouses.push({ name: item.warehouseName, qty: item.quantityDispatched }) + } + return Array.from(map.values()) + .map(({ shopSet, ...r }) => ({ ...r, shops: shopSet.size })) + .sort((a, b) => a.itemName.localeCompare(b.itemName)) +} + interface LoadingSheetViewSheetProps { open: boolean onClose: () => void @@ -40,11 +74,15 @@ function Row({ label, value }: { label: string; value: React.ReactNode }) { } export function LoadingSheetViewSheet({ open, onClose, sheet }: LoadingSheetViewSheetProps) { + const summary = useMemo(() => (sheet ? buildSummary(sheet.items) : []), [sheet]) + if (!sheet) return null + const totalQty = sheet.items.reduce((s, i) => s + i.quantityDispatched, 0) + return ( !v && onClose()}> - + Loading Sheet Details @@ -55,40 +93,51 @@ export function LoadingSheetViewSheet({ open, onClose, sheet }: LoadingSheetView {sheet.status}} /> - 0 ? sheet.orders.map(o => truncId(o.shopPOId)).join(', ') : '—'} />
-

Items ({sheet.items.length})

+

Loading Summary (item-wise)

- + + - {sheet.items.length === 0 ? ( + {summary.length === 0 ? ( - ) : ( - sheet.items.map((item) => ( - - - - + summary.map((row) => ( + + + + + )) )} + {summary.length > 0 && ( + + + + + + + )}
Item WarehouseQtyShopsTotal Qty
+ No items on this sheet.
{item.itemName}{item.warehouseName}{item.quantityDispatched}
{row.itemName} + {row.warehouses.map((w) => `${w.name} (${w.qty})`).join(', ')} + {row.shops}{row.total}
Grand total{totalQty}
diff --git a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheets-client.tsx b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheets-client.tsx index e510d08..e2b4320 100644 --- a/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheets-client.tsx +++ b/distribution_fe/app/(dashboard)/operations/loading/_components/loading-sheets-client.tsx @@ -193,7 +193,7 @@ export function LoadingSheetsClient() { }, ], rowActions: { - actions: () => [ + actions: (target) => [ { action: 'view', label: 'View sheet', @@ -201,9 +201,8 @@ export function LoadingSheetsClient() { }, { action: 'edit', - label: 'Set items', + label: target.status === 'Confirmed' ? 'Add items (new sheet)' : 'Set items', onClick: handleSetItems, - visible: (target) => target.status === 'Planned', }, { action: 'confirm', diff --git a/distribution_fe/app/(dashboard)/operations/loading/new/page.tsx b/distribution_fe/app/(dashboard)/operations/loading/new/page.tsx index 38dff7b..2ff1a7c 100644 --- a/distribution_fe/app/(dashboard)/operations/loading/new/page.tsx +++ b/distribution_fe/app/(dashboard)/operations/loading/new/page.tsx @@ -3,7 +3,15 @@ import { useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/navigation' import { HugeiconsIcon } from '@hugeicons/react' -import { ArrowLeft01Icon } from '@hugeicons/core-free-icons' +import { ArrowLeft01Icon, ViewIcon } from '@hugeicons/core-free-icons' +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from '@/components/ui/dialog' import { Select, SelectContent, @@ -46,7 +54,9 @@ interface PickedLine { shopPOItemId: string itemId: string itemName: string + storeId: string storeName: string + shopPOId: string orderedQty: number remainingQty: number checked: boolean @@ -70,6 +80,8 @@ export default function NewLoadingSheetPage() { const [rideId, setRideId] = useState('') const [populatedByUserId, setPopulatedByUserId] = useState('') + const [viewStoreId, setViewStoreId] = useState('') + const [pos, setPos] = useState([]) const [loadingPos, setLoadingPos] = useState(false) const [submitting, setSubmitting] = useState(false) @@ -103,6 +115,7 @@ export default function NewLoadingSheetPage() { useEffect(() => { setStoreId('') + setViewStoreId('') setLines({}) if (!routeId) { setStoresList([]) @@ -135,7 +148,9 @@ export default function NewLoadingSheetPage() { shopPOItemId: item.id, itemId: item.itemId, itemName: item.itemName, + storeId: po.storeId, storeName: po.storeName, + shopPOId: po.id, orderedQty: item.quantity, remainingQty: remaining, checked: false, @@ -156,6 +171,31 @@ export default function NewLoadingSheetPage() { [selectedRows, lines] ) + const shopGroups = useMemo(() => { + const map = new Map; rows: PickedLine[] }>() + for (const row of rows) { + const g = map.get(row.storeId) ?? { storeId: row.storeId, storeName: row.storeName, poIds: new Set(), rows: [] } + g.rows.push(row) + g.poIds.add(row.shopPOId) + map.set(row.storeId, g) + } + return Array.from(map.values()).sort((a, b) => a.storeName.localeCompare(b.storeName)) + }, [rows]) + + const viewGroup = shopGroups.find((g) => g.storeId === viewStoreId) + + const itemSummary = useMemo(() => { + const map = new Map }>() + for (const row of selectedRows) { + const qty = Number(lines[row.shopPOItemId]?.quantity) || 0 + const e = map.get(row.itemId) ?? { itemName: row.itemName, qty: 0, shops: new Set() } + e.qty += qty + e.shops.add(row.storeId) + map.set(row.itemId, e) + } + return Array.from(map.values()).sort((a, b) => a.itemName.localeCompare(b.itemName)) + }, [selectedRows, lines]) + function toggleLine(line: PickedLine, checked: boolean) { setLines((prev) => ({ ...prev, [line.shopPOItemId]: { ...line, checked } })) } @@ -198,9 +238,15 @@ export default function NewLoadingSheetPage() { setSubmitting(true) try { - const sheet = await loadingSheetsApi.create({ fK_RideId: rideId, populatedByUserId }) + const existing = getPaginatedItems( + await loadingSheetsApi.list({ rideId, status: 'Planned', pageSize: 1 }) + )[0] + const sheet = existing ?? await loadingSheetsApi.create({ fK_RideId: rideId, populatedByUserId }) await loadingSheetsApi.updateItems(sheet.id, items) - toast.add({ title: 'Loading sheet created', type: 'success' }) + toast.add({ + title: existing ? 'Items added to the ride\'s existing planned loading sheet' : 'Loading sheet created', + type: 'success', + }) router.push('/operations/loading') } catch (err) { toast.add({ title: 'Failed to create loading sheet', description: getApiError(err), type: 'error' }) @@ -232,10 +278,10 @@ export default function NewLoadingSheetPage() {
setRouteId(v ?? '')}> - + - + {routesList.map((r) => ( {r.routeName} ))} @@ -265,10 +311,10 @@ export default function NewLoadingSheetPage() { onValueChange={(v) => setStoreId(!v || v === ALL ? '' : v)} disabled={!routeId} > - + - + All shops on route {storesList.map((s) => ( {s.storeName} @@ -280,10 +326,10 @@ export default function NewLoadingSheetPage() {
setLineQuantity(row, Number(e.target.value))} - /> - - - ) - }) - )} - - +
+ {!routeId ? ( +

Select a route to see its shops with confirmed Shop POs.

+ ) : loadingPos ? ( +

Loading…

+ ) : shopGroups.length === 0 ? ( +

No shops with confirmed Shop POs found for this route.

+ ) : ( + shopGroups.map((group) => { + const groupLines = group.rows.map((r) => lines[r.shopPOItemId] ?? r) + const allChecked = groupLines.every((l) => l.checked) + const someChecked = groupLines.some((l) => l.checked) + return ( +
+ group.rows.forEach((r) => toggleLine(lines[r.shopPOItemId] ?? r, v === true))} + /> + {group.storeName} + + {group.poIds.size} PO{group.poIds.size === 1 ? '' : 's'} + + +
+ ) + }) + )}
+ + !v && setViewStoreId('')}> + + + {viewGroup?.storeName} + + Confirmed PO items. Tick the items to load and set the quantity. + + +
+ + + + + + + + + + + + {viewGroup?.rows.map((row) => { + const line = lines[row.shopPOItemId] ?? row + return ( + + + + + + + + ) + })} + +
ItemPOOrderedQty to load
+ toggleLine(row, v === true)} + /> + {row.itemName}{row.shopPOId.substring(0, 8)}{row.remainingQty} + setLineQuantity(row, Number(e.target.value))} + /> +
+
+ + + +
+
@@ -360,10 +449,10 @@ export default function NewLoadingSheetPage() {
setPopulatedByUserId(v ?? '')}> - + - + {usersList.map((u) => ( {u.fullName} ))} @@ -391,8 +480,8 @@ export default function NewLoadingSheetPage() {
-
-
+
+

Loading Sheet Summary

{selectedRows.length} item{selectedRows.length === 1 ? '' : 's'} selected. @@ -400,18 +489,38 @@ export default function NewLoadingSheetPage() { +

+ {itemSummary.length === 0 ? ( +

Tick shops or items to build the summary.

+ ) : ( + itemSummary.map((e) => ( +
+ + {e.itemName} + + {e.shops.size} shop{e.shops.size === 1 ? '' : 's'} + + + {e.qty} +
+ )) + )} +
+ + +

Total Quantity

{totalQuantity}

-
- +
+
diff --git a/distribution_fe/config/nav.ts b/distribution_fe/config/nav.ts index fa863d2..0ab7029 100644 --- a/distribution_fe/config/nav.ts +++ b/distribution_fe/config/nav.ts @@ -50,15 +50,6 @@ export const DASHBOARD_ITEM: NavItem = { } export const NAV_GROUPS: NavGroup[] = [ - { - title: 'Operations', - icon: TruckIcon, - items: [ - { title: 'Rides', href: '/operations/rides', icon: TruckIcon, description: 'Delivery/Sales runs assigned to a driver and vehicle', permission: 'rides.view' }, - { title: 'Loading Sheets', href: '/operations/loading', icon: DeliveryBox01Icon, description: 'Track goods loaded onto a vehicle before dispatch', permission: 'loading.view' }, - { title: 'Delivery Tasks', href: '/operations/deliveries', icon: DeliveryTruck01Icon, description: 'Individual store drop-offs within a ride', permission: 'rides.view' }, - ], - }, { title: 'Shop POs & Invoices', icon: DollarSquareIcon, @@ -68,11 +59,20 @@ export const NAV_GROUPS: NavGroup[] = [ { title: 'Payments', href: '/sales/payments', icon: BankIcon, description: 'Cash and credit payments collected against invoices', permission: 'orders.view' }, ], }, + { + title: 'Operations', + icon: TruckIcon, + items: [ + { title: 'Rides', href: '/operations/rides', icon: TruckIcon, description: 'Delivery/Sales runs assigned to a driver and vehicle', permission: 'rides.view' }, + { title: 'Loading Sheets', href: '/operations/loading', icon: DeliveryBox01Icon, description: 'Track goods loaded onto a vehicle before dispatch', permission: 'loading.view' }, + { title: 'Delivery Tasks', href: '/operations/deliveries', icon: DeliveryTruck01Icon, description: 'Individual store drop-offs within a ride', permission: 'rides.view' }, + ], + }, { title: 'Stores', icon: Store01Icon, items: [ - { title: 'Stores', href: '/stores', icon: Store01Icon, description: 'Retail store accounts, credit limits, and KYC status', permission: 'stores.view' }, + { title: 'Stores', href: '/stores', icon: Store01Icon, description: 'Retail store accounts, credit limits and balances', permission: 'stores.view' }, { title: 'Sales Visits', href: '/sales-visits', icon: Location01Icon, description: 'Check in and out of scheduled store visits', permission: 'sales_visits.checkin' }, ], }, diff --git a/distribution_fe/lib/api/master.ts b/distribution_fe/lib/api/master.ts index 97a0c0e..b7c7656 100644 --- a/distribution_fe/lib/api/master.ts +++ b/distribution_fe/lib/api/master.ts @@ -128,9 +128,9 @@ export const regions = { export interface RouteBody { regionId: string routeName: string - startPoint: string - endPoint: string - length: number + startPoint?: string | null + endPoint?: string | null + length?: number | null isActive?: boolean } diff --git a/distribution_fe/lib/api/sales.ts b/distribution_fe/lib/api/sales.ts index d07de9f..f9ddd00 100644 --- a/distribution_fe/lib/api/sales.ts +++ b/distribution_fe/lib/api/sales.ts @@ -58,8 +58,8 @@ export const shopPos = { confirmAndCreateInvoice: (id: string, confirmedByUserId?: string | null) => api.post(`/shop-pos/${id}/confirm-and-create-invoice`, { confirmedByUserId }).then(r => r.data), - cancel: (id: string) => - api.post(`/shop-pos/${id}/cancel`).then(r => r.data), + cancel: (id: string, reason: string, cancelledByUserId?: string | null) => + api.post(`/shop-pos/${id}/cancel`, { reason, cancelledByUserId }).then(r => r.data), } // ─── Invoices ───────────────────────────────────────────────────────────────── diff --git a/distribution_fe/types/api.ts b/distribution_fe/types/api.ts index 955781d..a3ccbf7 100644 --- a/distribution_fe/types/api.ts +++ b/distribution_fe/types/api.ts @@ -1,6 +1,5 @@ // ─── Enums ──────────────────────────────────────────────────────────────────── -export type KycStatus = 'Pending' | 'Verified' | 'Rejected' export type LocationType = 'Warehouse' | 'Vehicle' | 'External' export type MovementType = | 'Sale' | 'CustomerReturn' | 'Transfer' | 'Damage' @@ -81,9 +80,9 @@ export interface RouteResponse { id: string regionId: string routeName: string - startPoint: string - endPoint: string - length: number + startPoint: string | null + endPoint: string | null + length: number | null ownerUserId: string | null isActive: boolean createdAt: string @@ -200,7 +199,8 @@ export interface WarehouseResponse { export interface StoreResponse { id: string routeId: string - ownerName: string + ownerName: string | null + contactNumber: string | null storeName: string storeAddress: string latitude: number @@ -210,19 +210,10 @@ export interface StoreResponse { creditLimit: number outstandingBalance: number segment: string | null - kycStatus: KycStatus isActive: boolean createdAt: string } -export interface KycDocumentResponse { - id: string - storeId: string - documentType: string - fileReference: string - uploadedAt: string -} - export interface OutstandingBalanceResponse { storeId: string creditLimit: number @@ -576,6 +567,9 @@ export interface LoadingSheetItemResponse { warehouseName: string quantityDispatched: number fK_ShopPOItemId: string | null + shopPOId: string | null + storeId: string | null + storeName: string | null } export interface LoadingSheetOrderRef { @@ -646,6 +640,15 @@ export interface ShopPOResponse { items: ShopPOItemResponse[] isActive: boolean createdAt: string + raisedByName: string | null + raisedByRole: string | null + confirmedByName: string | null + confirmedByRole: string | null + cancelledBy: string | null + cancelledAt: string | null + cancelReason: string | null + cancelledByName: string | null + cancelledByRole: string | null } export interface InvoiceResponse {