product and sales fixers
This commit is contained in:
@@ -5,10 +5,12 @@ import { ApiResult, EntityStatus, PagedResponse } from "@/types/common"
|
||||
import {
|
||||
CreateItemRequest,
|
||||
Item,
|
||||
ItemImage,
|
||||
ItemListItem,
|
||||
ItemOverview,
|
||||
ItemReorderSetting,
|
||||
ItemScanResult,
|
||||
StockNature,
|
||||
TrackingMode,
|
||||
UpdateItemReorderRequest,
|
||||
UpdateItemRequest,
|
||||
@@ -34,8 +36,13 @@ export interface ListItemOverviewParams {
|
||||
categoryId?: number
|
||||
subCategoryId?: number
|
||||
brandId?: number
|
||||
trackingMode?: TrackingMode
|
||||
stockNature?: StockNature
|
||||
stock?: ItemStockFilter
|
||||
}
|
||||
|
||||
export type ItemStockFilter = "InStock" | "OutOfStock" | "LowStock"
|
||||
|
||||
export const itemsApi = {
|
||||
list(params: ListItemsParams = {}): Promise<PagedResponse<ItemListItem>> {
|
||||
return apiRequest<PagedResponse<ItemListItem>>(`/items${buildQuery(params)}`)
|
||||
@@ -46,6 +53,25 @@ export const itemsApi = {
|
||||
overview(params: ListItemOverviewParams = {}): Promise<PagedResponse<ItemOverview>> {
|
||||
return apiRequest<PagedResponse<ItemOverview>>(`/items/overview${buildQuery(params)}`)
|
||||
},
|
||||
listImages(itemId: number): Promise<ItemImage[]> {
|
||||
return apiRequest<ItemImage[]>(`/items/${itemId}/images`)
|
||||
},
|
||||
|
||||
/** JPG/PNG/WebP, ≤ 5 MB, ≤ 10 per item. 422 CONFIG_DISABLED while item images are off. */
|
||||
uploadImage(itemId: number, file: File): Promise<ItemImage> {
|
||||
const form = new FormData()
|
||||
form.append("file", file)
|
||||
return apiRequest<ItemImage>(`/items/${itemId}/images`, { method: "POST", body: form })
|
||||
},
|
||||
|
||||
deleteImage(itemId: number, itemImageId: number): Promise<void> {
|
||||
return apiRequest<void>(`/items/${itemId}/images/${itemImageId}`, { method: "DELETE" })
|
||||
},
|
||||
|
||||
/** Same-origin and cookie-authenticated, so it works directly as an <img> src. */
|
||||
imageUrl(itemId: number, itemImageId: number): string {
|
||||
return `/api/v1/items/${itemId}/images/${itemImageId}/content`
|
||||
},
|
||||
|
||||
get(itemId: number): Promise<ApiResult<Item>> {
|
||||
return apiRequestWithETag<Item>(`/items/${itemId}`)
|
||||
|
||||
@@ -16,8 +16,7 @@ export const productConfigApi = {
|
||||
/** All flags are required; a partial body is a 400, never a silent disable. */
|
||||
update(request: UpdateProductConfigRequest, ifMatch: string): Promise<ApiResult<ProductConfig>> {
|
||||
return apiRequestWithETag<ProductConfig>("/product-config", { method: "PUT", body: request, ifMatch })
|
||||
},
|
||||
}
|
||||
},}
|
||||
|
||||
/** Read-only helper for screens that only need the flags. */
|
||||
export function productConfig(): Promise<ProductConfig> {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Sales configuration. Singleton - no id. When `allowCashCustomer` is on, sales can be raised
|
||||
// against the generic "Cash Customer" (`cashCustomerId`) and New Sale defaults to it; when off,
|
||||
// a real customer must be picked (the server rejects the cash customer).
|
||||
import { apiRequestWithETag } from "@/lib/api-client"
|
||||
import { ApiResult } from "@/types/common"
|
||||
import { SalesConfig, UpdateSalesConfigRequest } from "@/types/sales"
|
||||
|
||||
export const salesConfigApi = {
|
||||
get(): Promise<ApiResult<SalesConfig>> {
|
||||
return apiRequestWithETag<SalesConfig>("/sales-config")
|
||||
},
|
||||
|
||||
update(request: UpdateSalesConfigRequest, ifMatch: string): Promise<ApiResult<SalesConfig>> {
|
||||
return apiRequestWithETag<SalesConfig>("/sales-config", { method: "PUT", body: request, ifMatch })
|
||||
},
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
SalesSlipStatus,
|
||||
SalesSlipPostingCheck,
|
||||
SalesSlipSummary,
|
||||
SalesStockAvailability,
|
||||
SalesSuggestedPrice,
|
||||
UpdateSalesInvoiceRequest,
|
||||
UpdateSalesSlipRequest,
|
||||
} from "@/types/sales"
|
||||
@@ -46,6 +48,16 @@ export const salesApi = {
|
||||
return apiRequest<PagedResponse<SalesInvoiceSummary>>(`/sales-invoices${buildQuery(params)}`)
|
||||
},
|
||||
|
||||
/** Unit price a line would get on save when left blank (flat price, else GRN/FIFO average). */
|
||||
getSuggestedPrice(itemId: number, warehouseId: number): Promise<SalesSuggestedPrice> {
|
||||
return apiRequest<SalesSuggestedPrice>(`/sales-invoices/suggested-price${buildQuery({ itemId, warehouseId })}`)
|
||||
},
|
||||
|
||||
/** Issuable stock for an item at a warehouse — New Sale's per-line shortage warning. */
|
||||
getStockAvailability(itemId: number, warehouseId: number): Promise<SalesStockAvailability> {
|
||||
return apiRequest<SalesStockAvailability>(`/sales-invoices/stock-availability${buildQuery({ itemId, warehouseId })}`)
|
||||
},
|
||||
|
||||
getInvoice(salesInvoiceId: number): Promise<ApiResult<SalesInvoice>> {
|
||||
return apiRequestWithETag<SalesInvoice>(`/sales-invoices/${salesInvoiceId}`)
|
||||
},
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Custom warranty period master (Products → Warranty Periods). Defaults (3/6/12/18 months)
|
||||
// are fixed client+server side and not returned here.
|
||||
import { apiRequest, buildQuery } from "@/lib/api-client"
|
||||
import { EntityStatus } from "@/types/common"
|
||||
import { WarrantyPeriod } from "@/types/master-data"
|
||||
|
||||
export const warrantyPeriodsApi = {
|
||||
list(params: { status?: EntityStatus } = {}): Promise<WarrantyPeriod[]> {
|
||||
return apiRequest<WarrantyPeriod[]>(`/warranty-periods${buildQuery(params)}`)
|
||||
},
|
||||
|
||||
/** Months 1–600, not a default. Re-adding an inactive length reactivates it; an active duplicate is 409. */
|
||||
create(months: number): Promise<WarrantyPeriod> {
|
||||
return apiRequest<WarrantyPeriod>("/warranty-periods", { method: "POST", body: { months } })
|
||||
},
|
||||
|
||||
/** Deactivate/reactivate — there is no DELETE (FR-MD-08). */
|
||||
updateStatus(warrantyPeriodId: number, status: EntityStatus): Promise<void> {
|
||||
return apiRequest<void>(`/warranty-periods/${warrantyPeriodId}/status`, { method: "PATCH", body: { status } })
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user