diff --git a/backend/patches/createInventoryNumberSeries.ts b/backend/patches/createInventoryNumberSeries.ts index 4b4e6c56..2852691a 100644 --- a/backend/patches/createInventoryNumberSeries.ts +++ b/backend/patches/createInventoryNumberSeries.ts @@ -2,19 +2,33 @@ import { getDefaultMetaFieldValueMap } from '../../backend/helpers'; import { DatabaseManager } from '../database/manager'; async function execute(dm: DatabaseManager) { - const schemaName = 'NumberSeries'; - const name = 'SMOV-'; - const exists = await dm.db?.exists(schemaName, name); + const names: Record = { + StockMovement: 'SMOV-', + Shipment: 'SHP-', + }; + + for (const referenceType in names) { + const name = names[referenceType]; + await createNumberSeries(name, referenceType, dm); + } +} + +async function createNumberSeries( + name: string, + referenceType: string, + dm: DatabaseManager +) { + const exists = await dm.db?.exists('NumberSeries', name); if (exists) { return; } - await dm.db?.insert(schemaName, { + await dm.db?.insert('NumberSeries', { name, start: 1001, padZeros: 4, current: 0, - referenceType: 'StockMovement', + referenceType, ...getDefaultMetaFieldValueMap(), }); } diff --git a/fyo/core/converter.ts b/fyo/core/converter.ts index e8dab2c4..713b8de7 100644 --- a/fyo/core/converter.ts +++ b/fyo/core/converter.ts @@ -102,7 +102,7 @@ export class Converter { } #toDocValueMap(schemaName: string, rawValueMap: RawValueMap): DocValueMap { - const fieldValueMap = this.db.fieldValueMap[schemaName]; + const fieldValueMap = this.db.fieldMap[schemaName]; const docValueMap: DocValueMap = {}; for (const fieldname in rawValueMap) { @@ -130,7 +130,7 @@ export class Converter { } #toRawValueMap(schemaName: string, docValueMap: DocValueMap): RawValueMap { - const fieldValueMap = this.db.fieldValueMap[schemaName]; + const fieldValueMap = this.db.fieldMap[schemaName]; const rawValueMap: RawValueMap = {}; for (const fieldname in docValueMap) { diff --git a/fyo/core/dbHandler.ts b/fyo/core/dbHandler.ts index d4675000..c02d826e 100644 --- a/fyo/core/dbHandler.ts +++ b/fyo/core/dbHandler.ts @@ -10,7 +10,7 @@ import { DatabaseBase, DatabaseDemuxBase, GetAllOptions, - QueryFilter, + QueryFilter } from 'utils/db/types'; import { schemaTranslateables } from 'utils/translationHelpers'; import { LanguageMap } from 'utils/types'; @@ -19,7 +19,7 @@ import { DatabaseDemuxConstructor, DocValue, DocValueMap, - RawValueMap, + RawValueMap } from './types'; // Return types of Bespoke Queries @@ -33,6 +33,7 @@ type TotalCreditAndDebit = { totalCredit: number; totalDebit: number; }; +type FieldMap = Record>; export class DatabaseHandler extends DatabaseBase { #fyo: Fyo; @@ -40,8 +41,8 @@ export class DatabaseHandler extends DatabaseBase { #demux: DatabaseDemuxBase; dbPath?: string; #schemaMap: SchemaMap = {}; + #fieldMap: FieldMap = {}; observer: Observable = new Observable(); - fieldValueMap: Record> = {}; constructor(fyo: Fyo, Demux?: DatabaseDemuxConstructor) { super(); @@ -59,6 +60,10 @@ export class DatabaseHandler extends DatabaseBase { return this.#schemaMap; } + get fieldMap(): Readonly { + return this.#fieldMap; + } + get isConnected() { return !!this.dbPath; } @@ -79,11 +84,7 @@ export class DatabaseHandler extends DatabaseBase { async init() { this.#schemaMap = (await this.#demux.getSchemaMap()) as SchemaMap; - - for (const schemaName in this.schemaMap) { - const fields = this.schemaMap[schemaName]!.fields!; - this.fieldValueMap[schemaName] = getMapFromList(fields, 'fieldname'); - } + this.#setFieldMap(); this.observer = new Observable(); } @@ -92,6 +93,7 @@ export class DatabaseHandler extends DatabaseBase { translateSchema(this.#schemaMap, languageMap, schemaTranslateables); } else { this.#schemaMap = (await this.#demux.getSchemaMap()) as SchemaMap; + this.#setFieldMap(); } } @@ -99,7 +101,7 @@ export class DatabaseHandler extends DatabaseBase { await this.close(); this.dbPath = undefined; this.#schemaMap = {}; - this.fieldValueMap = {}; + this.#fieldMap = {}; } async insert( @@ -166,7 +168,7 @@ export class DatabaseHandler extends DatabaseBase { const docSingleValue: SingleValue = []; for (const sv of rawSingleValue) { - const field = this.fieldValueMap[sv.parent][sv.fieldname]; + const field = this.fieldMap[sv.parent][sv.fieldname]; const value = Converter.toDocValue(sv.value, field, this.#fyo); docSingleValue.push({ @@ -334,4 +336,15 @@ export class DatabaseHandler extends DatabaseBase { options )) as RawValueMap[]; } + + #setFieldMap() { + this.#fieldMap = Object.values(this.schemaMap).reduce((acc, sch) => { + if (!sch?.name) { + return acc; + } + + acc[sch?.name] = getMapFromList(sch?.fields, 'fieldname'); + return acc; + }, {} as FieldMap); + } } diff --git a/fyo/index.ts b/fyo/index.ts index 166fcc15..e370df7d 100644 --- a/fyo/index.ts +++ b/fyo/index.ts @@ -84,6 +84,10 @@ export class Fyo { return this.db.schemaMap; } + get fieldMap() { + return this.db.fieldMap; + } + format(value: DocValue, field: string | Field, doc?: Doc) { return format(value, field, doc ?? null, this); } @@ -163,8 +167,7 @@ export class Fyo { } getField(schemaName: string, fieldname: string) { - const schema = this.schemaMap[schemaName]; - return schema?.fields.find((f) => f.fieldname === fieldname); + return this.fieldMap[schemaName][fieldname]; } async getValue( diff --git a/models/index.ts b/models/index.ts index 937a4d34..d81b2198 100644 --- a/models/index.ts +++ b/models/index.ts @@ -18,6 +18,10 @@ import { SetupWizard } from './baseModels/SetupWizard/SetupWizard'; import { Tax } from './baseModels/Tax/Tax'; import { TaxSummary } from './baseModels/TaxSummary/TaxSummary'; import { Location } from './inventory/Location'; +import { PurchaseReceipt } from './inventory/PurchaseReceipt'; +import { PurchaseReceiptItem } from './inventory/PurchaseReceiptItem'; +import { Shipment } from './inventory/Shipment'; +import { ShipmentItem } from './inventory/ShipmentItem'; import { StockLedgerEntry } from './inventory/StockLedgerEntry'; import { StockMovement } from './inventory/StockMovement'; import { StockMovementItem } from './inventory/StockMovementItem'; @@ -46,6 +50,10 @@ export const models = { StockMovementItem, StockLedgerEntry, Location, + Shipment, + ShipmentItem, + PurchaseReceipt, + PurchaseReceiptItem, } as ModelMap; export async function getRegionalModels( diff --git a/models/inventory/PurchaseReceipt.ts b/models/inventory/PurchaseReceipt.ts new file mode 100644 index 00000000..490e2af5 --- /dev/null +++ b/models/inventory/PurchaseReceipt.ts @@ -0,0 +1,21 @@ +import { ListViewSettings } from 'fyo/model/types'; +import { getTransactionStatusColumn } from 'models/helpers'; +import { PurchaseReceiptItem } from './PurchaseReceiptItem'; +import { StockTransfer } from './StockTransfer'; + +export class PurchaseReceipt extends StockTransfer { + items?: PurchaseReceiptItem[]; + + static getListViewSettings(): ListViewSettings { + return { + formRoute: (name) => `/edit/PurchaseReceipt/${name}`, + columns: [ + 'name', + getTransactionStatusColumn(), + 'party', + 'date', + 'grandTotal', + ], + }; + } +} diff --git a/models/inventory/PurchaseReceiptItem.ts b/models/inventory/PurchaseReceiptItem.ts new file mode 100644 index 00000000..b33e939b --- /dev/null +++ b/models/inventory/PurchaseReceiptItem.ts @@ -0,0 +1,3 @@ +import { StockTransferItem } from './StockTransferItem'; + +export class PurchaseReceiptItem extends StockTransferItem {} diff --git a/models/inventory/Shipment.ts b/models/inventory/Shipment.ts new file mode 100644 index 00000000..8411601c --- /dev/null +++ b/models/inventory/Shipment.ts @@ -0,0 +1,21 @@ +import { ListViewSettings } from 'fyo/model/types'; +import { getTransactionStatusColumn } from 'models/helpers'; +import { ShipmentItem } from './ShipmentItem'; +import { StockTransfer } from './StockTransfer'; + +export class Shipment extends StockTransfer { + items?: ShipmentItem[]; + + static getListViewSettings(): ListViewSettings { + return { + formRoute: (name) => `/edit/Shipment/${name}`, + columns: [ + 'name', + getTransactionStatusColumn(), + 'party', + 'date', + 'grandTotal', + ], + }; + } +} diff --git a/models/inventory/ShipmentItem.ts b/models/inventory/ShipmentItem.ts new file mode 100644 index 00000000..16f197ea --- /dev/null +++ b/models/inventory/ShipmentItem.ts @@ -0,0 +1,3 @@ +import { StockTransferItem } from './StockTransferItem'; + +export class ShipmentItem extends StockTransferItem {} diff --git a/models/inventory/StockTransfer.ts b/models/inventory/StockTransfer.ts new file mode 100644 index 00000000..1d1088c6 --- /dev/null +++ b/models/inventory/StockTransfer.ts @@ -0,0 +1,10 @@ +import { Attachment } from 'fyo/core/types'; +import { Doc } from 'fyo/model/doc'; + +export abstract class StockTransfer extends Doc { + name?: string; + date?: string; + party?: string; + terms?: string; + attachment?: Attachment; +} diff --git a/models/inventory/StockTransferItem.ts b/models/inventory/StockTransferItem.ts new file mode 100644 index 00000000..44601a02 --- /dev/null +++ b/models/inventory/StockTransferItem.ts @@ -0,0 +1,13 @@ +import { Doc } from 'fyo/model/doc'; +import { Money } from 'pesa'; + +export class StockTransferItem extends Doc { + item?: string; + location?: string; + quantity?: number; + rate?: Money; + amount?: Money; + unit?: string; + description?: string; + hsnCode?: number; +} diff --git a/models/types.ts b/models/types.ts index e5800e5f..94bfaf03 100644 --- a/models/types.ts +++ b/models/types.ts @@ -33,6 +33,10 @@ export enum ModelNameEnum { StockMovement = 'StockMovement', StockMovementItem = 'StockMovementItem', StockLedgerEntry = 'StockLedgerEntry', + Shipment = 'Shipment', + ShipmentItem = 'ShipmentItem', + PurchaseReceipt = 'PurchaseReceipt', + PurchaseReceiptItem = 'PurchaseReceiptItem', Location = 'Location', } diff --git a/schemas/app/NumberSeries.json b/schemas/app/NumberSeries.json index 00be44aa..4da950b5 100644 --- a/schemas/app/NumberSeries.json +++ b/schemas/app/NumberSeries.json @@ -50,6 +50,14 @@ { "value": "StockMovement", "label": "Stock Movement" + }, + { + "value": "Shipment", + "label": "Shipment" + }, + { + "value": "PurchaseReceipt", + "label": "Purchase Receipt" } ], "default": "-", diff --git a/schemas/app/inventory/PurchaseReceipt.json b/schemas/app/inventory/PurchaseReceipt.json new file mode 100644 index 00000000..d3a23981 --- /dev/null +++ b/schemas/app/inventory/PurchaseReceipt.json @@ -0,0 +1,27 @@ +{ + "name": "PurchaseReceipt", + "label": "Purchase Receipt", + "extends": "StockTransfer", + "naming": "numberSeries", + "showTitle": true, + "fields": [ + { + "fieldname": "items", + "label": "Items", + "fieldtype": "Table", + "target": "PurchaseReceiptItem", + "required": true, + "edit": true + }, + { + "fieldname": "numberSeries", + "label": "Number Series", + "fieldtype": "Link", + "target": "NumberSeries", + "create": true, + "required": true, + "default": "PREC-" + } + ], + "keywordFields": ["name", "party"] +} diff --git a/schemas/app/inventory/PurchaseReceiptItem.json b/schemas/app/inventory/PurchaseReceiptItem.json new file mode 100644 index 00000000..5c142dd3 --- /dev/null +++ b/schemas/app/inventory/PurchaseReceiptItem.json @@ -0,0 +1,14 @@ +{ + "name": "PurchaseReceiptItem", + "label": "Purchase Receipt Item", + "extends": "StockTransferItem", + "fields": [ + { + "fieldname": "location", + "label": "Dest.", + "fieldtype": "Link", + "target": "Location", + "required": true + } + ] +} diff --git a/schemas/app/inventory/Shipment.json b/schemas/app/inventory/Shipment.json new file mode 100644 index 00000000..21902aef --- /dev/null +++ b/schemas/app/inventory/Shipment.json @@ -0,0 +1,27 @@ +{ + "name": "Shipment", + "label": "Shipment", + "extends": "StockTransfer", + "naming": "numberSeries", + "showTitle": true, + "fields": [ + { + "fieldname": "items", + "label": "Items", + "fieldtype": "Table", + "target": "ShipmentItem", + "required": true, + "edit": true + }, + { + "fieldname": "numberSeries", + "label": "Number Series", + "fieldtype": "Link", + "target": "NumberSeries", + "create": true, + "required": true, + "default": "SHPM-" + } + ], + "keywordFields": ["name", "party"] +} diff --git a/schemas/app/inventory/ShipmentItem.json b/schemas/app/inventory/ShipmentItem.json new file mode 100644 index 00000000..b95cd81e --- /dev/null +++ b/schemas/app/inventory/ShipmentItem.json @@ -0,0 +1,14 @@ +{ + "name": "ShipmentItem", + "label": "Shipment Item", + "extends": "StockTransferItem", + "fields": [ + { + "fieldname": "location", + "label": "Source", + "fieldtype": "Link", + "target": "Location", + "required": true + } + ] +} diff --git a/schemas/app/inventory/StockTransfer.json b/schemas/app/inventory/StockTransfer.json new file mode 100644 index 00000000..2cb6baac --- /dev/null +++ b/schemas/app/inventory/StockTransfer.json @@ -0,0 +1,50 @@ +{ + "name": "StockTransfer", + "label": "StockTransfer", + "isAbstract": true, + "isSingle": false, + "isChild": false, + "isSubmittable": true, + "fields": [ + { + "label": "Transfer No", + "fieldname": "name", + "fieldtype": "Data", + "required": true, + "readOnly": true + }, + { + "fieldname": "date", + "label": "Date", + "fieldtype": "Date", + "required": true + }, + { + "fieldname": "party", + "label": "Party", + "fieldtype": "Link", + "target": "Party", + "create": true, + "required": true + }, + { + "fieldname": "terms", + "label": "Notes", + "placeholder": "Add transfer terms", + "fieldtype": "Text" + }, + { + "fieldname": "attachment", + "placeholder": "Add attachment", + "label": "Attachment", + "fieldtype": "Attachment" + }, + { + "fieldname": "grandTotal", + "label": "Grand Total", + "fieldtype": "Currency", + "readOnly": true + } + ], + "keywordFields": ["name", "party"] +} diff --git a/schemas/app/inventory/StockTransferItem.json b/schemas/app/inventory/StockTransferItem.json new file mode 100644 index 00000000..464cdd8e --- /dev/null +++ b/schemas/app/inventory/StockTransferItem.json @@ -0,0 +1,71 @@ +{ + "name": "StockTransferItem", + "label": "Stock Transfer Item", + "isAbstract": true, + "isChild": true, + "fields": [ + { + "fieldname": "item", + "label": "Item", + "fieldtype": "Link", + "target": "Item", + "required": true + }, + { + "fieldname": "location", + "fieldtype": "Link", + "target": "Location", + "required": true + }, + { + "fieldname": "quantity", + "label": "Quantity", + "fieldtype": "Float", + "required": true, + "default": 1 + }, + { + "fieldname": "rate", + "label": "Rate", + "fieldtype": "Currency", + "required": true + }, + { + "fieldname": "amount", + "label": "Amount", + "fieldtype": "Currency", + "readOnly": true + }, + { + "fieldname": "unit", + "label": "Unit Type", + "fieldtype": "Link", + "target": "UOM", + "default": "Unit", + "placeholder": "Unit Type" + }, + { + "fieldname": "description", + "label": "Description", + "placeholder": "Item Description", + "fieldtype": "Text" + }, + { + "fieldname": "hsnCode", + "label": "HSN/SAC", + "fieldtype": "Int", + "placeholder": "HSN/SAC Code" + } + ], + "tableFields": ["item", "location", "quantity", "rate", "amount"], + "quickEditFields": [ + "item", + "unit", + "description", + "hsnCode", + "location", + "quantity", + "rate", + "amount" + ] +} diff --git a/schemas/schemas.ts b/schemas/schemas.ts index 654758bc..878650f0 100644 --- a/schemas/schemas.ts +++ b/schemas/schemas.ts @@ -8,9 +8,15 @@ import Currency from './app/Currency.json'; import Defaults from './app/Defaults.json'; import GetStarted from './app/GetStarted.json'; import Location from './app/inventory/Location.json'; +import PurchaseReceipt from './app/inventory/PurchaseReceipt.json'; +import PurchaseReceiptItem from './app/inventory/PurchaseReceiptItem.json'; +import Shipment from './app/inventory/Shipment.json'; +import ShipmentItem from './app/inventory/ShipmentItem.json'; import StockLedgerEntry from './app/inventory/StockLedgerEntry.json'; import StockMovement from './app/inventory/StockMovement.json'; import StockMovementItem from './app/inventory/StockMovementItem.json'; +import StockTransfer from './app/inventory/StockTransfer.json'; +import StockTransferItem from './app/inventory/StockTransferItem.json'; import Invoice from './app/Invoice.json'; import InvoiceItem from './app/InvoiceItem.json'; import Item from './app/Item.json'; @@ -97,4 +103,11 @@ export const appSchemas: Schema[] | SchemaStub[] = [ StockLedgerEntry as Schema, StockMovement as Schema, StockMovementItem as Schema, + + StockTransfer as Schema, + StockTransferItem as Schema, + Shipment as Schema, + ShipmentItem as Schema, + PurchaseReceipt as Schema, + PurchaseReceiptItem as Schema, ]; diff --git a/src/components/Controls/FormControl.vue b/src/components/Controls/FormControl.vue index 02230c01..555c9858 100644 --- a/src/components/Controls/FormControl.vue +++ b/src/components/Controls/FormControl.vue @@ -38,6 +38,9 @@ const components = { export default { name: 'FormControl', render() { + if (!this.$attrs.df) { + console.log(this); + } const fieldtype = this.$attrs.df.fieldtype; const component = components[fieldtype] ?? Data; diff --git a/src/pages/GeneralForm.vue b/src/pages/GeneralForm.vue new file mode 100644 index 00000000..10e2f5ad --- /dev/null +++ b/src/pages/GeneralForm.vue @@ -0,0 +1,267 @@ + + diff --git a/src/router.ts b/src/router.ts index fe5f8197..9e076d0c 100644 --- a/src/router.ts +++ b/src/router.ts @@ -2,6 +2,7 @@ import { ModelNameEnum } from 'models/types'; import ChartOfAccounts from 'src/pages/ChartOfAccounts.vue'; import Dashboard from 'src/pages/Dashboard/Dashboard.vue'; import DataImport from 'src/pages/DataImport.vue'; +import GeneralForm from 'src/pages/GeneralForm.vue'; import GetStarted from 'src/pages/GetStarted.vue'; import InvoiceForm from 'src/pages/InvoiceForm.vue'; import JournalEntryForm from 'src/pages/JournalEntryForm.vue'; @@ -12,6 +13,31 @@ import Report from 'src/pages/Report.vue'; import Settings from 'src/pages/Settings/Settings.vue'; import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; +function getGeneralFormItems(): RouteRecordRaw[] { + return [ModelNameEnum.Shipment, ModelNameEnum.PurchaseReceipt].map( + (schemaName) => { + return { + path: `/edit/${schemaName}/:name`, + name: `${schemaName}Form`, + components: { + default: GeneralForm, + edit: QuickEditForm, + }, + props: { + default: (route) => { + route.params.schemaName = schemaName; + return { + schemaName, + name: route.params.name, + }; + }, + edit: (route) => route.query, + }, + }; + } + ); +} + const routes: RouteRecordRaw[] = [ { path: '/', @@ -21,6 +47,7 @@ const routes: RouteRecordRaw[] = [ path: '/get-started', component: GetStarted, }, + ...getGeneralFormItems(), { path: '/edit/JournalEntry/:name', name: 'JournalEntryForm', @@ -122,6 +149,7 @@ const routes: RouteRecordRaw[] = [ }, }, ]; +console.log(routes); export function getEntryRoute(schemaName: string, name: string) { if ( diff --git a/src/utils/sidebarConfig.ts b/src/utils/sidebarConfig.ts index f087ffd6..24920daf 100644 --- a/src/utils/sidebarConfig.ts +++ b/src/utils/sidebarConfig.ts @@ -82,6 +82,18 @@ async function getInventorySidebar(): Promise { route: '/list/StockMovement', schemaName: 'StockMovement', }, + { + label: t`Shipment`, + name: 'shipment', + route: '/list/Shipment', + schemaName: 'Shipment', + }, + { + label: t`Purchase Receipt`, + name: 'purchase-receipt', + route: '/list/PurchaseReceipt', + schemaName: 'PurchaseReceipt', + }, ], }, ];