auto generate grn on import arrival unloading

This commit is contained in:
Hagernesh
2026-07-21 07:21:35 +00:00
parent db466a6b27
commit 36f0045b5d
4 changed files with 130 additions and 14 deletions

View File

@@ -13,6 +13,19 @@ import { ReceiveInventoryModal } from './ReceiveInventoryModal';
interface WarehouseInfoCardProps {
bookingId: string;
bookingReference?: string;
/**
* Booking payment status. Export cargo is received into the warehouse only
* after the booking is paid — receiving an unpaid booking starts storage and
* GRN against cargo the customer has not settled. Optional so existing callers
* that do not have the booking to hand keep their current behaviour.
*/
paymentStatus?: string | null;
/**
* IMPORT | EXPORT | DOMESTIC. The payment gate is export-only: import cargo
* arrives OFF a train, so blocking its receive would strand cargo already at
* the yard.
*/
tradeDirection?: string | null;
}
function Row({ label, value }: { label: string; value: React.ReactNode }) {
@@ -28,7 +41,12 @@ function Row({ label, value }: { label: string; value: React.ReactNode }) {
);
}
export function WarehouseInfoCard({ bookingId, bookingReference }: WarehouseInfoCardProps) {
export function WarehouseInfoCard({
bookingId,
bookingReference,
paymentStatus,
tradeDirection,
}: WarehouseInfoCardProps) {
const [modalOpen, setModalOpen] = useState(false);
const { data, isLoading } = useQuery(
api.warehouses.listInventory.queryOptions({ input: { filter: { bookingId } } }),
@@ -46,6 +64,13 @@ export function WarehouseInfoCard({ bookingId, bookingReference }: WarehouseInfo
const wagon = scheduleView?.wagon;
const isLoadedOrDispatched =
latest?.status === 'LOADED' || latest?.status === 'DISPATCHED';
// Export only, and only when we were actually told the status — an absent prop
// means the caller cannot answer, and guessing "unpaid" would disable a valid
// action. Mirrors the server guard on receive().
const awaitingPayment =
tradeDirection?.toUpperCase() === 'EXPORT' &&
paymentStatus != null &&
paymentStatus.toUpperCase() !== 'PAID';
return (
<Card withBorder radius="md" padding="lg">
@@ -127,8 +152,12 @@ export function WarehouseInfoCard({ bookingId, bookingReference }: WarehouseInfo
)}
<Tooltip
label="This booking is already received at the warehouse"
disabled={!latest}
label={
latest
? 'This booking is already received at the warehouse'
: 'This booking is not paid yet — cargo can only be received once payment is settled'
}
disabled={!latest && !awaitingPayment}
withArrow
>
{/* span wrapper so the tooltip still fires on the disabled button */}
@@ -138,7 +167,7 @@ export function WarehouseInfoCard({ bookingId, bookingReference }: WarehouseInfo
leftSection={<PackagePlus size={16} />}
onClick={() => setModalOpen(true)}
fullWidth
disabled={Boolean(latest)}
disabled={Boolean(latest) || awaitingPayment}
>
{latest ? 'Received At Warehouse' : 'Receive At Warehouse'}
</Button>