mirror of
https://github.com/frappe/books.git
synced 2024-11-09 15:20:56 +00:00
incr: add Purchase Recipt & Shipment scaffolding
This commit is contained in:
parent
a9fd590512
commit
cf37077b6d
@ -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<string, string> = {
|
||||
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(),
|
||||
});
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<string, Record<string, Field>>;
|
||||
|
||||
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<never> = new Observable();
|
||||
fieldValueMap: Record<string, Record<string, Field>> = {};
|
||||
|
||||
constructor(fyo: Fyo, Demux?: DatabaseDemuxConstructor) {
|
||||
super();
|
||||
@ -59,6 +60,10 @@ export class DatabaseHandler extends DatabaseBase {
|
||||
return this.#schemaMap;
|
||||
}
|
||||
|
||||
get fieldMap(): Readonly<FieldMap> {
|
||||
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<DocValue> = [];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
21
models/inventory/PurchaseReceipt.ts
Normal file
21
models/inventory/PurchaseReceipt.ts
Normal file
@ -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',
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
3
models/inventory/PurchaseReceiptItem.ts
Normal file
3
models/inventory/PurchaseReceiptItem.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { StockTransferItem } from './StockTransferItem';
|
||||
|
||||
export class PurchaseReceiptItem extends StockTransferItem {}
|
21
models/inventory/Shipment.ts
Normal file
21
models/inventory/Shipment.ts
Normal file
@ -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',
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
3
models/inventory/ShipmentItem.ts
Normal file
3
models/inventory/ShipmentItem.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { StockTransferItem } from './StockTransferItem';
|
||||
|
||||
export class ShipmentItem extends StockTransferItem {}
|
10
models/inventory/StockTransfer.ts
Normal file
10
models/inventory/StockTransfer.ts
Normal file
@ -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;
|
||||
}
|
13
models/inventory/StockTransferItem.ts
Normal file
13
models/inventory/StockTransferItem.ts
Normal file
@ -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;
|
||||
}
|
@ -33,6 +33,10 @@ export enum ModelNameEnum {
|
||||
StockMovement = 'StockMovement',
|
||||
StockMovementItem = 'StockMovementItem',
|
||||
StockLedgerEntry = 'StockLedgerEntry',
|
||||
Shipment = 'Shipment',
|
||||
ShipmentItem = 'ShipmentItem',
|
||||
PurchaseReceipt = 'PurchaseReceipt',
|
||||
PurchaseReceiptItem = 'PurchaseReceiptItem',
|
||||
Location = 'Location',
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,14 @@
|
||||
{
|
||||
"value": "StockMovement",
|
||||
"label": "Stock Movement"
|
||||
},
|
||||
{
|
||||
"value": "Shipment",
|
||||
"label": "Shipment"
|
||||
},
|
||||
{
|
||||
"value": "PurchaseReceipt",
|
||||
"label": "Purchase Receipt"
|
||||
}
|
||||
],
|
||||
"default": "-",
|
||||
|
27
schemas/app/inventory/PurchaseReceipt.json
Normal file
27
schemas/app/inventory/PurchaseReceipt.json
Normal file
@ -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"]
|
||||
}
|
14
schemas/app/inventory/PurchaseReceiptItem.json
Normal file
14
schemas/app/inventory/PurchaseReceiptItem.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "PurchaseReceiptItem",
|
||||
"label": "Purchase Receipt Item",
|
||||
"extends": "StockTransferItem",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "location",
|
||||
"label": "Dest.",
|
||||
"fieldtype": "Link",
|
||||
"target": "Location",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
27
schemas/app/inventory/Shipment.json
Normal file
27
schemas/app/inventory/Shipment.json
Normal file
@ -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"]
|
||||
}
|
14
schemas/app/inventory/ShipmentItem.json
Normal file
14
schemas/app/inventory/ShipmentItem.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "ShipmentItem",
|
||||
"label": "Shipment Item",
|
||||
"extends": "StockTransferItem",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "location",
|
||||
"label": "Source",
|
||||
"fieldtype": "Link",
|
||||
"target": "Location",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
50
schemas/app/inventory/StockTransfer.json
Normal file
50
schemas/app/inventory/StockTransfer.json
Normal file
@ -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"]
|
||||
}
|
71
schemas/app/inventory/StockTransferItem.json
Normal file
71
schemas/app/inventory/StockTransferItem.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
@ -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,
|
||||
];
|
||||
|
@ -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;
|
||||
|
||||
|
267
src/pages/GeneralForm.vue
Normal file
267
src/pages/GeneralForm.vue
Normal file
@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<FormContainer>
|
||||
<!-- Page Header (Title, Buttons, etc) -->
|
||||
<template #header v-if="doc">
|
||||
<StatusBadge :status="status" />
|
||||
<DropdownWithActions :actions="actions()" />
|
||||
<Button
|
||||
v-if="doc?.notInserted || doc?.dirty"
|
||||
type="primary"
|
||||
@click="sync"
|
||||
>
|
||||
{{ t`Save` }}
|
||||
</Button>
|
||||
<Button
|
||||
v-if="!doc?.dirty && !doc?.notInserted && !doc?.submitted"
|
||||
type="primary"
|
||||
@click="submit"
|
||||
>{{ t`Submit` }}</Button
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- Form Header -->
|
||||
<template #body v-if="doc">
|
||||
<FormHeader
|
||||
:form-title="doc.notInserted ? t`New Entry` : doc.name"
|
||||
:form-sub-title="doc.schema?.label ?? ''"
|
||||
/>
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<!-- Invoice Form Data Entry -->
|
||||
<div class="m-4 grid grid-cols-3 gap-4">
|
||||
<FormControl
|
||||
input-class="font-semibold"
|
||||
:border="true"
|
||||
:df="getField('party')"
|
||||
:value="doc.party"
|
||||
@change="(value) => doc.set('party', value, true)"
|
||||
@new-doc="(party) => doc.set('party', party.name, true)"
|
||||
:read-only="doc?.submitted"
|
||||
/>
|
||||
<FormControl
|
||||
input-class="text-right"
|
||||
:border="true"
|
||||
:df="getField('date')"
|
||||
:value="doc.date"
|
||||
@change="(value) => doc.set('date', value)"
|
||||
:read-only="doc?.submitted"
|
||||
/>
|
||||
<FormControl
|
||||
input-class="text-right"
|
||||
:border="true"
|
||||
:df="getField('numberSeries')"
|
||||
:value="doc.numberSeries"
|
||||
@change="(value) => doc.set('numberSeries', value)"
|
||||
:read-only="!doc.notInserted || doc?.submitted"
|
||||
/>
|
||||
<FormControl
|
||||
v-if="doc.attachment || !(doc.isSubmitted || doc.isCancelled)"
|
||||
:border="true"
|
||||
:df="getField('attachment')"
|
||||
:value="doc.attachment"
|
||||
@change="(value) => doc.set('attachment', value)"
|
||||
:read-only="doc?.submitted"
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<!-- Invoice Items Table -->
|
||||
<Table
|
||||
class="text-base"
|
||||
:df="getField('items')"
|
||||
:value="doc.items"
|
||||
:showHeader="true"
|
||||
:max-rows-before-overflow="4"
|
||||
@change="(value) => doc.set('items', value)"
|
||||
@editrow="toggleQuickEditDoc"
|
||||
:read-only="doc?.submitted"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Invoice Form Footer -->
|
||||
|
||||
<div v-if="doc.items?.length ?? 0" class="mt-auto">
|
||||
<hr />
|
||||
<div class="flex justify-between text-base m-4 gap-12">
|
||||
<div class="w-1/2 flex flex-col justify-between">
|
||||
<!-- Form Terms-->
|
||||
<FormControl
|
||||
:border="true"
|
||||
v-if="!doc?.submitted || doc.terms"
|
||||
:df="getField('terms')"
|
||||
:value="doc.terms"
|
||||
class="mt-auto"
|
||||
@change="(value) => doc.set('terms', value)"
|
||||
:read-only="doc?.submitted"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #quickedit v-if="quickEditDoc">
|
||||
<QuickEditForm
|
||||
class="w-quick-edit"
|
||||
:name="quickEditDoc.name"
|
||||
:show-name="false"
|
||||
:show-save="false"
|
||||
:source-doc="quickEditDoc"
|
||||
:source-fields="quickEditFields"
|
||||
:schema-name="quickEditDoc.schemaName"
|
||||
:white="true"
|
||||
:route-back="false"
|
||||
:load-on-close="false"
|
||||
@close="toggleQuickEditDoc(null)"
|
||||
/>
|
||||
</template>
|
||||
</FormContainer>
|
||||
</template>
|
||||
<script>
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { getDocStatus } from 'models/helpers';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import Table from 'src/components/Controls/Table.vue';
|
||||
import DropdownWithActions from 'src/components/DropdownWithActions.vue';
|
||||
import FormContainer from 'src/components/FormContainer.vue';
|
||||
import FormHeader from 'src/components/FormHeader.vue';
|
||||
import StatusBadge from 'src/components/StatusBadge.vue';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { docsPathMap } from 'src/utils/misc';
|
||||
import {
|
||||
docsPath,
|
||||
getActionsForDocument,
|
||||
routeTo,
|
||||
showMessageDialog,
|
||||
} from 'src/utils/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import { handleErrorWithDialog } from '../errorHandling';
|
||||
import QuickEditForm from './QuickEditForm.vue';
|
||||
|
||||
export default {
|
||||
name: 'InvoiceForm',
|
||||
props: { schemaName: String, name: String },
|
||||
components: {
|
||||
StatusBadge,
|
||||
Button,
|
||||
FormControl,
|
||||
DropdownWithActions,
|
||||
Table,
|
||||
FormContainer,
|
||||
QuickEditForm,
|
||||
FormHeader,
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
schemaName: this.schemaName,
|
||||
name: this.name,
|
||||
doc: computed(() => this.doc),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chstatus: false,
|
||||
doc: null,
|
||||
quickEditDoc: null,
|
||||
quickEditFields: [],
|
||||
printSettings: null,
|
||||
};
|
||||
},
|
||||
updated() {
|
||||
this.chstatus = !this.chstatus;
|
||||
},
|
||||
computed: {
|
||||
status() {
|
||||
this.chstatus;
|
||||
return getDocStatus(this.doc);
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
docsPath.value = docsPathMap[this.schemaName];
|
||||
},
|
||||
deactivated() {
|
||||
docsPath.value = '';
|
||||
},
|
||||
async mounted() {
|
||||
try {
|
||||
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
|
||||
} catch (error) {
|
||||
if (error instanceof fyo.errors.NotFoundError) {
|
||||
routeTo(`/list/${this.schemaName}`);
|
||||
return;
|
||||
}
|
||||
await this.handleError(error);
|
||||
}
|
||||
|
||||
let query = this.$route.query;
|
||||
if (query.values && query.schemaName === this.schemaName) {
|
||||
this.doc.set(this.$router.currentRoute.value.query.values);
|
||||
}
|
||||
|
||||
if (fyo.store.isDevelopment) {
|
||||
window.frm = this;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
routeTo,
|
||||
async toggleQuickEditDoc(doc, fields = []) {
|
||||
if (this.quickEditDoc && doc) {
|
||||
this.quickEditDoc = null;
|
||||
this.quickEditFields = [];
|
||||
await nextTick();
|
||||
}
|
||||
|
||||
this.quickEditDoc = doc;
|
||||
this.quickEditFields = fields;
|
||||
},
|
||||
actions() {
|
||||
return getActionsForDocument(this.doc);
|
||||
},
|
||||
getField(fieldname) {
|
||||
return fyo.getField(this.schemaName, fieldname);
|
||||
},
|
||||
async sync() {
|
||||
try {
|
||||
await this.doc.sync();
|
||||
} catch (err) {
|
||||
await this.handleError(err);
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
const message = t`Submit ${this.doc.name}`;
|
||||
const ref = this;
|
||||
await showMessageDialog({
|
||||
message,
|
||||
buttons: [
|
||||
{
|
||||
label: this.t`Yes`,
|
||||
async action() {
|
||||
try {
|
||||
await ref.doc.submit();
|
||||
} catch (err) {
|
||||
await ref.handleError(err);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: this.t`No`,
|
||||
action() {},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
async handleError(e) {
|
||||
await handleErrorWithDialog(e, this.doc);
|
||||
},
|
||||
formattedValue(fieldname, doc) {
|
||||
if (!doc) {
|
||||
doc = this.doc;
|
||||
}
|
||||
|
||||
const df = this.getField(fieldname);
|
||||
return fyo.format(doc[fieldname], df, doc);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -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 (
|
||||
|
@ -82,6 +82,18 @@ async function getInventorySidebar(): Promise<SidebarRoot[]> {
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user