2de9e5e4ad
Introduced "ModeB" for manual invoice creation in system config. Added backend endpoints and service logic for creating invoices from confirmed Shop POs, with validation and error handling. Updated DTOs to support optional CreatedByUserId. On the frontend, added configuration card to toggle modes, a dialog for manual invoice creation, and UI updates to support the new workflow. Enables admins to choose between automatic and manual invoice creation.
91 lines
3.1 KiB
TypeScript
91 lines
3.1 KiB
TypeScript
import { api } from '@/lib/api'
|
|
import type { SysConfigResponse } from '@/types/api'
|
|
|
|
// ─── Item tracking feature keys (must match Distribution.Features.SysConfig.SysConfigService) ──
|
|
|
|
export const ITEM_TRACKING_KEYS = {
|
|
serialNumberTracking: 'Feature.SerialNumberTracking',
|
|
batchTracking: 'Feature.BatchTracking',
|
|
expiryDateTracking: 'Feature.ExpiryDateTracking',
|
|
warrantyTracking: 'Feature.WarrantyTracking',
|
|
customWarrantyOverride: 'Feature.CustomWarrantyOverride',
|
|
defaultWarrantyPeriodDays: 'Feature.DefaultWarrantyPeriodDays',
|
|
} as const
|
|
|
|
export const sysConfig = {
|
|
getAll: () =>
|
|
api.get<SysConfigResponse[]>('/sys-config').then(r => r.data),
|
|
|
|
get: (key: string) =>
|
|
api.get<SysConfigResponse>(`/sys-config/${key}`).then(r => r.data),
|
|
|
|
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])))),
|
|
}
|
|
|
|
// ─── Invoice creation mode (must match Distribution.Features.SysConfig.SysConfigService) ─────
|
|
|
|
export const INVOICE_CREATION_MODE_KEY = 'InvoiceCreationMode'
|
|
|
|
export type InvoiceCreationMode = 'ModeA' | 'ModeB'
|
|
|
|
export const DEFAULT_INVOICE_CREATION_MODE: InvoiceCreationMode = 'ModeB'
|
|
|
|
export const invoiceCreationMode = {
|
|
get: () =>
|
|
api.get<{ mode: InvoiceCreationMode }>('/sys-config/invoice-creation-mode').then(r => r.data.mode),
|
|
|
|
set: (mode: InvoiceCreationMode) =>
|
|
api.put('/sys-config/invoice-creation-mode', { mode }).then(r => r.data),
|
|
}
|