Refactor GRN configuration page layout
This commit is contained in:
@@ -11,7 +11,7 @@ export { stock } from './stock'
|
||||
export { productReports } from './reports'
|
||||
export { shopPos, invoices, payments } from './sales'
|
||||
export { saleReturns, claims, supplierClaims } from './returns-claims'
|
||||
export { sysConfig, ITEM_TRACKING_KEYS } from './sys-config'
|
||||
export { sysConfig, ITEM_TRACKING_KEYS, GRN_TAX_KEYS, grnTaxSettings, DEFAULT_GRN_TAX_SETTINGS } from './sys-config'
|
||||
export { getPaginatedItems } from './paginated'
|
||||
|
||||
export type { PageParams } from './master'
|
||||
|
||||
@@ -82,6 +82,7 @@ export interface GrnItemBody {
|
||||
/** Omitted falls back to the GRN-wide percentage. */
|
||||
discountPercent?: number
|
||||
vatPercent?: number
|
||||
nbtPercent?: number
|
||||
/** Free-issue units: stocked but not costed. Serials/batches must cover accepted + free. */
|
||||
freeQuantity?: number
|
||||
}
|
||||
@@ -94,6 +95,7 @@ export interface GrnBody {
|
||||
/** GRN-wide defaults for lines that don't set their own. */
|
||||
discountPercent?: number
|
||||
vatPercent?: number
|
||||
nbtPercent?: number
|
||||
// TEMPORARY: required while auth doesn't resolve a logged-in user server-side — see testbug.md #28.
|
||||
receivedByUserId: string
|
||||
}
|
||||
@@ -104,6 +106,7 @@ export interface DirectGrnBody {
|
||||
items: GrnItemBody[]
|
||||
discountPercent?: number
|
||||
vatPercent?: number
|
||||
nbtPercent?: number
|
||||
// TEMPORARY: required while auth doesn't resolve a logged-in user server-side — see testbug.md #28.
|
||||
receivedByUserId: string
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ export const stock = {
|
||||
adjust: (body: AdjustmentBody) =>
|
||||
api.post('/stock/adjustment', body).then(r => r.data),
|
||||
|
||||
/** Next free number for auto-generated serials: one past the highest `<prefix><digits>` already saved for the item. */
|
||||
nextSerialSequence: (itemId: string, prefix: string) =>
|
||||
api
|
||||
.get<{ next: number }>('/stock/serials/next-sequence', { params: { itemId, prefix } })
|
||||
.then(r => r.data.next),
|
||||
|
||||
updateMovementReason: (id: string, reasonCode: string) =>
|
||||
api.patch(`/stock/movements/${id}/reason`, { reasonCode }).then(r => r.data),
|
||||
}
|
||||
|
||||
@@ -22,3 +22,53 @@ export const sysConfig = {
|
||||
set: (key: string, value: string, userId?: string | null) =>
|
||||
api.put<SysConfigResponse>(`/sys-config/${key}`, { value, userId }).then(r => r.data),
|
||||
}
|
||||
|
||||
// ─── GRN tax settings (must match Distribution.Features.SysConfig.SysConfigService) ──────────
|
||||
|
||||
export type TaxMode = 'Disabled' | 'Optional' | 'Mandatory'
|
||||
|
||||
export const GRN_TAX_KEYS = {
|
||||
vatMode: 'Grn.Tax.Vat.Mode',
|
||||
vatRate: 'Grn.Tax.Vat.DefaultRate',
|
||||
nbtMode: 'Grn.Tax.Nbt.Mode',
|
||||
nbtRate: 'Grn.Tax.Nbt.DefaultRate',
|
||||
} as const
|
||||
|
||||
export interface GrnTaxSettings {
|
||||
vatMode: TaxMode
|
||||
vatDefaultRate: number
|
||||
nbtMode: TaxMode
|
||||
nbtDefaultRate: number
|
||||
}
|
||||
|
||||
const TAX_MODES: TaxMode[] = ['Disabled', 'Optional', 'Mandatory']
|
||||
|
||||
/** Unconfigured, VAT is Optional (as GRNs behaved before the setting existed) and NBT is off. */
|
||||
export const DEFAULT_GRN_TAX_SETTINGS: GrnTaxSettings = {
|
||||
vatMode: 'Optional',
|
||||
vatDefaultRate: 0,
|
||||
nbtMode: 'Disabled',
|
||||
nbtDefaultRate: 0,
|
||||
}
|
||||
|
||||
export function parseGrnTaxSettings(byKey: Record<string, string>): GrnTaxSettings {
|
||||
const mode = (raw: string | undefined, fallback: TaxMode): TaxMode =>
|
||||
TAX_MODES.includes(raw as TaxMode) ? (raw as TaxMode) : fallback
|
||||
const rate = (raw: string | undefined) => {
|
||||
const n = Number(raw)
|
||||
return raw !== undefined && Number.isFinite(n) && n >= 0 && n <= 100 ? n : 0
|
||||
}
|
||||
return {
|
||||
vatMode: mode(byKey[GRN_TAX_KEYS.vatMode], DEFAULT_GRN_TAX_SETTINGS.vatMode),
|
||||
vatDefaultRate: rate(byKey[GRN_TAX_KEYS.vatRate]),
|
||||
nbtMode: mode(byKey[GRN_TAX_KEYS.nbtMode], DEFAULT_GRN_TAX_SETTINGS.nbtMode),
|
||||
nbtDefaultRate: rate(byKey[GRN_TAX_KEYS.nbtRate]),
|
||||
}
|
||||
}
|
||||
|
||||
export const grnTaxSettings = {
|
||||
get: () =>
|
||||
sysConfig
|
||||
.getAll()
|
||||
.then(all => parseGrnTaxSettings(Object.fromEntries(all.map(c => [c.key, c.value])))),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user