cost and price
This commit is contained in:
@@ -156,6 +156,10 @@ export function InventoryDetailPage() {
|
|||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Default cost</dt>
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Default cost</dt>
|
||||||
<dd className="mt-2 text-sm text-text">{item.defaultCost == null ? "Not set" : `$${item.defaultCost.toFixed(2)}`}</dd>
|
<dd className="mt-2 text-sm text-text">{item.defaultCost == null ? "Not set" : `$${item.defaultCost.toFixed(2)}`}</dd>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Default price</dt>
|
||||||
|
<dd className="mt-2 text-sm text-text">{item.defaultPrice == null ? "Not set" : `$${item.defaultPrice.toFixed(2)}`}</dd>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Flags</dt>
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted">Flags</dt>
|
||||||
<dd className="mt-2 text-sm text-text">
|
<dd className="mt-2 text-sm text-text">
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
isSellable: item.isSellable,
|
isSellable: item.isSellable,
|
||||||
isPurchasable: item.isPurchasable,
|
isPurchasable: item.isPurchasable,
|
||||||
defaultCost: item.defaultCost,
|
defaultCost: item.defaultCost,
|
||||||
|
defaultPrice: item.defaultPrice,
|
||||||
notes: item.notes,
|
notes: item.notes,
|
||||||
bomLines: item.bomLines.map((line) => ({
|
bomLines: item.bomLines.map((line) => ({
|
||||||
componentItemId: line.componentItemId,
|
componentItemId: line.componentItemId,
|
||||||
@@ -199,6 +200,17 @@ export function InventoryFormPage({ mode }: InventoryFormPageProps) {
|
|||||||
className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
<label className="block">
|
||||||
|
<span className="mb-2 block text-sm font-semibold text-text">Default price</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min={0}
|
||||||
|
step={0.01}
|
||||||
|
value={form.defaultPrice ?? ""}
|
||||||
|
onChange={(event) => updateField("defaultPrice", event.target.value === "" ? null : Number(event.target.value))}
|
||||||
|
className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-3 xl:grid-cols-4">
|
<div className="grid gap-3 xl:grid-cols-4">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export const emptyInventoryItemInput: InventoryItemInput = {
|
|||||||
isSellable: true,
|
isSellable: true,
|
||||||
isPurchasable: true,
|
isPurchasable: true,
|
||||||
defaultCost: null,
|
defaultCost: null,
|
||||||
|
defaultPrice: null,
|
||||||
notes: "",
|
notes: "",
|
||||||
bomLines: [],
|
bomLines: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ export function SalesFormPage({ entity, mode }: { entity: SalesDocumentEntity; m
|
|||||||
...line,
|
...line,
|
||||||
itemId: option.id,
|
itemId: option.id,
|
||||||
description: line.description || option.name,
|
description: line.description || option.name,
|
||||||
|
unitPrice: line.unitPrice > 0 ? line.unitPrice : (option.defaultPrice ?? 0),
|
||||||
});
|
});
|
||||||
updateLineSearchTerm(index, option.sku);
|
updateLineSearchTerm(index, option.sku);
|
||||||
setActiveLinePicker(null);
|
setActiveLinePicker(null);
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "InventoryItem" ADD COLUMN "defaultPrice" REAL;
|
||||||
@@ -113,6 +113,7 @@ model InventoryItem {
|
|||||||
isSellable Boolean @default(true)
|
isSellable Boolean @default(true)
|
||||||
isPurchasable Boolean @default(true)
|
isPurchasable Boolean @default(true)
|
||||||
defaultCost Float?
|
defaultCost Float?
|
||||||
|
defaultPrice Float?
|
||||||
notes String
|
notes String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ export async function bootstrapAppData() {
|
|||||||
isSellable: false,
|
isSellable: false,
|
||||||
isPurchasable: true,
|
isPurchasable: true,
|
||||||
defaultCost: 42.5,
|
defaultCost: 42.5,
|
||||||
|
defaultPrice: null,
|
||||||
notes: "Primary sheet stock for enclosure fabrication.",
|
notes: "Primary sheet stock for enclosure fabrication.",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -191,6 +192,7 @@ export async function bootstrapAppData() {
|
|||||||
isSellable: false,
|
isSellable: false,
|
||||||
isPurchasable: true,
|
isPurchasable: true,
|
||||||
defaultCost: 0.18,
|
defaultCost: 0.18,
|
||||||
|
defaultPrice: null,
|
||||||
notes: "Bulk hardware item.",
|
notes: "Bulk hardware item.",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -206,6 +208,7 @@ export async function bootstrapAppData() {
|
|||||||
isSellable: true,
|
isSellable: true,
|
||||||
isPurchasable: false,
|
isPurchasable: false,
|
||||||
defaultCost: 118,
|
defaultCost: 118,
|
||||||
|
defaultPrice: 249,
|
||||||
notes: "Starter BOM for the inventory foundation slice.",
|
notes: "Starter BOM for the inventory foundation slice.",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const inventoryItemSchema = z.object({
|
|||||||
isSellable: z.boolean(),
|
isSellable: z.boolean(),
|
||||||
isPurchasable: z.boolean(),
|
isPurchasable: z.boolean(),
|
||||||
defaultCost: z.number().nonnegative().nullable(),
|
defaultCost: z.number().nonnegative().nullable(),
|
||||||
|
defaultPrice: z.number().nonnegative().nullable(),
|
||||||
notes: z.string(),
|
notes: z.string(),
|
||||||
bomLines: z.array(bomLineSchema),
|
bomLines: z.array(bomLineSchema),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type InventoryDetailRecord = {
|
|||||||
isSellable: boolean;
|
isSellable: boolean;
|
||||||
isPurchasable: boolean;
|
isPurchasable: boolean;
|
||||||
defaultCost: number | null;
|
defaultCost: number | null;
|
||||||
|
defaultPrice: number | null;
|
||||||
notes: string;
|
notes: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
@@ -220,6 +221,7 @@ function mapDetail(record: InventoryDetailRecord): InventoryItemDetailDto {
|
|||||||
}),
|
}),
|
||||||
description: record.description,
|
description: record.description,
|
||||||
defaultCost: record.defaultCost,
|
defaultCost: record.defaultCost,
|
||||||
|
defaultPrice: record.defaultPrice,
|
||||||
notes: record.notes,
|
notes: record.notes,
|
||||||
createdAt: record.createdAt.toISOString(),
|
createdAt: record.createdAt.toISOString(),
|
||||||
bomLines: record.bomLines.slice().sort((a, b) => a.position - b.position).map(mapBomLine),
|
bomLines: record.bomLines.slice().sort((a, b) => a.position - b.position).map(mapBomLine),
|
||||||
@@ -371,6 +373,7 @@ export async function listInventoryItemOptions() {
|
|||||||
id: true,
|
id: true,
|
||||||
sku: true,
|
sku: true,
|
||||||
name: true,
|
name: true,
|
||||||
|
defaultPrice: true,
|
||||||
},
|
},
|
||||||
orderBy: [{ sku: "asc" }],
|
orderBy: [{ sku: "asc" }],
|
||||||
});
|
});
|
||||||
@@ -379,6 +382,7 @@ export async function listInventoryItemOptions() {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
sku: item.sku,
|
sku: item.sku,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
|
defaultPrice: item.defaultPrice,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,6 +521,7 @@ export async function createInventoryItem(payload: InventoryItemInput) {
|
|||||||
isSellable: payload.isSellable,
|
isSellable: payload.isSellable,
|
||||||
isPurchasable: payload.isPurchasable,
|
isPurchasable: payload.isPurchasable,
|
||||||
defaultCost: payload.defaultCost,
|
defaultCost: payload.defaultCost,
|
||||||
|
defaultPrice: payload.defaultPrice,
|
||||||
notes: payload.notes,
|
notes: payload.notes,
|
||||||
bomLines: validatedBom.bomLines.length
|
bomLines: validatedBom.bomLines.length
|
||||||
? {
|
? {
|
||||||
@@ -558,6 +563,7 @@ export async function updateInventoryItem(itemId: string, payload: InventoryItem
|
|||||||
isSellable: payload.isSellable,
|
isSellable: payload.isSellable,
|
||||||
isPurchasable: payload.isPurchasable,
|
isPurchasable: payload.isPurchasable,
|
||||||
defaultCost: payload.defaultCost,
|
defaultCost: payload.defaultCost,
|
||||||
|
defaultPrice: payload.defaultPrice,
|
||||||
notes: payload.notes,
|
notes: payload.notes,
|
||||||
bomLines: {
|
bomLines: {
|
||||||
deleteMany: {},
|
deleteMany: {},
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export interface InventoryItemOptionDto {
|
|||||||
id: string;
|
id: string;
|
||||||
sku: string;
|
sku: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
defaultPrice: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WarehouseLocationOptionDto {
|
export interface WarehouseLocationOptionDto {
|
||||||
@@ -128,6 +129,7 @@ export interface InventoryTransactionInput {
|
|||||||
export interface InventoryItemDetailDto extends InventoryItemSummaryDto {
|
export interface InventoryItemDetailDto extends InventoryItemSummaryDto {
|
||||||
description: string;
|
description: string;
|
||||||
defaultCost: number | null;
|
defaultCost: number | null;
|
||||||
|
defaultPrice: number | null;
|
||||||
notes: string;
|
notes: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
bomLines: InventoryBomLineDto[];
|
bomLines: InventoryBomLineDto[];
|
||||||
@@ -146,6 +148,7 @@ export interface InventoryItemInput {
|
|||||||
isSellable: boolean;
|
isSellable: boolean;
|
||||||
isPurchasable: boolean;
|
isPurchasable: boolean;
|
||||||
defaultCost: number | null;
|
defaultCost: number | null;
|
||||||
|
defaultPrice: number | null;
|
||||||
notes: string;
|
notes: string;
|
||||||
bomLines: InventoryBomLineInput[];
|
bomLines: InventoryBomLineInput[];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user