mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
Merge pull request #566 from frappe/redo-settings
fix(ui): make settings use common form format
This commit is contained in:
commit
51ce718d01
@ -177,11 +177,12 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get canSave() {
|
get canSave() {
|
||||||
if (!!this.submitted) {
|
const isSubmittable = this.schema.isSubmittable;
|
||||||
|
if (isSubmittable && !!this.submitted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!this.cancelled) {
|
if (isSubmittable && !!this.cancelled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,10 +190,6 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.schema.isSingle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.schema.isChild) {
|
if (this.schema.isChild) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Doc } from 'fyo/model/doc';
|
|||||||
import {
|
import {
|
||||||
ChangeArg,
|
ChangeArg,
|
||||||
FiltersMap,
|
FiltersMap,
|
||||||
|
HiddenMap,
|
||||||
ListsMap,
|
ListsMap,
|
||||||
ReadOnlyMap,
|
ReadOnlyMap,
|
||||||
ValidationMap,
|
ValidationMap,
|
||||||
@ -46,6 +47,11 @@ export class AccountingSettings extends Doc {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
override hidden: HiddenMap = {
|
||||||
|
discountAccount: () => !this.enableDiscounting,
|
||||||
|
gstin: () => this.fyo.singles.SystemSettings?.countryCode !== 'in',
|
||||||
|
};
|
||||||
|
|
||||||
async change(ch: ChangeArg) {
|
async change(ch: ChangeArg) {
|
||||||
const discountingEnabled =
|
const discountingEnabled =
|
||||||
ch.changed === 'enableDiscounting' && this.enableDiscounting;
|
ch.changed === 'enableDiscounting' && this.enableDiscounting;
|
||||||
|
@ -11,7 +11,6 @@ import {
|
|||||||
ValidationMap,
|
ValidationMap,
|
||||||
} from 'fyo/model/types';
|
} from 'fyo/model/types';
|
||||||
import { ValidationError } from 'fyo/utils/errors';
|
import { ValidationError } from 'fyo/utils/errors';
|
||||||
import { ModelNameEnum } from 'models/types';
|
|
||||||
import { Money } from 'pesa';
|
import { Money } from 'pesa';
|
||||||
import { AccountRootTypeEnum, AccountTypeEnum } from '../Account/types';
|
import { AccountRootTypeEnum, AccountTypeEnum } from '../Account/types';
|
||||||
|
|
||||||
|
8
models/baseModels/PrintSettings/PrintSettings.ts
Normal file
8
models/baseModels/PrintSettings/PrintSettings.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Doc } from 'fyo/model/doc';
|
||||||
|
import { HiddenMap } from 'fyo/model/types';
|
||||||
|
|
||||||
|
export class PrintSettings extends Doc {
|
||||||
|
override hidden: HiddenMap = {
|
||||||
|
displayBatch: () => !this.fyo.singles.InventorySettings?.enableBatches,
|
||||||
|
};
|
||||||
|
}
|
@ -10,6 +10,7 @@ import { JournalEntryAccount } from './baseModels/JournalEntryAccount/JournalEnt
|
|||||||
import { Party } from './baseModels/Party/Party';
|
import { Party } from './baseModels/Party/Party';
|
||||||
import { Payment } from './baseModels/Payment/Payment';
|
import { Payment } from './baseModels/Payment/Payment';
|
||||||
import { PaymentFor } from './baseModels/PaymentFor/PaymentFor';
|
import { PaymentFor } from './baseModels/PaymentFor/PaymentFor';
|
||||||
|
import { PrintSettings } from './baseModels/PrintSettings/PrintSettings';
|
||||||
import { PurchaseInvoice } from './baseModels/PurchaseInvoice/PurchaseInvoice';
|
import { PurchaseInvoice } from './baseModels/PurchaseInvoice/PurchaseInvoice';
|
||||||
import { PurchaseInvoiceItem } from './baseModels/PurchaseInvoiceItem/PurchaseInvoiceItem';
|
import { PurchaseInvoiceItem } from './baseModels/PurchaseInvoiceItem/PurchaseInvoiceItem';
|
||||||
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
||||||
@ -17,6 +18,7 @@ import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem
|
|||||||
import { SetupWizard } from './baseModels/SetupWizard/SetupWizard';
|
import { SetupWizard } from './baseModels/SetupWizard/SetupWizard';
|
||||||
import { Tax } from './baseModels/Tax/Tax';
|
import { Tax } from './baseModels/Tax/Tax';
|
||||||
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
|
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
|
||||||
|
import { Batch } from './inventory/Batch';
|
||||||
import { InventorySettings } from './inventory/InventorySettings';
|
import { InventorySettings } from './inventory/InventorySettings';
|
||||||
import { Location } from './inventory/Location';
|
import { Location } from './inventory/Location';
|
||||||
import { PurchaseReceipt } from './inventory/PurchaseReceipt';
|
import { PurchaseReceipt } from './inventory/PurchaseReceipt';
|
||||||
@ -26,7 +28,6 @@ import { ShipmentItem } from './inventory/ShipmentItem';
|
|||||||
import { StockLedgerEntry } from './inventory/StockLedgerEntry';
|
import { StockLedgerEntry } from './inventory/StockLedgerEntry';
|
||||||
import { StockMovement } from './inventory/StockMovement';
|
import { StockMovement } from './inventory/StockMovement';
|
||||||
import { StockMovementItem } from './inventory/StockMovementItem';
|
import { StockMovementItem } from './inventory/StockMovementItem';
|
||||||
import { Batch } from './inventory/Batch';
|
|
||||||
|
|
||||||
export const models = {
|
export const models = {
|
||||||
Account,
|
Account,
|
||||||
@ -41,6 +42,7 @@ export const models = {
|
|||||||
Party,
|
Party,
|
||||||
Payment,
|
Payment,
|
||||||
PaymentFor,
|
PaymentFor,
|
||||||
|
PrintSettings,
|
||||||
PurchaseInvoice,
|
PurchaseInvoice,
|
||||||
PurchaseInvoiceItem,
|
PurchaseInvoiceItem,
|
||||||
SalesInvoice,
|
SalesInvoice,
|
||||||
|
@ -5,87 +5,100 @@
|
|||||||
"isChild": false,
|
"isChild": false,
|
||||||
"isSubmittable": false,
|
"isSubmittable": false,
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"label": "Full Name",
|
||||||
|
"fieldname": "fullname",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"required": true,
|
||||||
|
"section": "Default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Company Name",
|
"label": "Company Name",
|
||||||
"fieldname": "companyName",
|
"fieldname": "companyName",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"required": true
|
"required": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Write Off Account",
|
"label": "Bank Name",
|
||||||
"fieldname": "writeOffAccount",
|
"fieldname": "bankName",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Data",
|
||||||
"target": "Account"
|
"readOnly": true,
|
||||||
|
"required": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Round Off Account",
|
|
||||||
"fieldname": "roundOffAccount",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"target": "Account"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "country",
|
|
||||||
"label": "Country",
|
"label": "Country",
|
||||||
|
"fieldname": "country",
|
||||||
"fieldtype": "AutoComplete",
|
"fieldtype": "AutoComplete",
|
||||||
"placeholder": "Select Country",
|
"placeholder": "Select Country",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"required": true
|
"required": true,
|
||||||
},
|
"section": "Default"
|
||||||
{
|
|
||||||
"fieldname": "fullname",
|
|
||||||
"label": "Full Name",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"required": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "email",
|
"fieldname": "email",
|
||||||
"label": "Email",
|
"label": "Email",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"required": true
|
"required": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "bankName",
|
"label": "Write Off Account",
|
||||||
"label": "Bank Name",
|
"fieldname": "writeOffAccount",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Link",
|
||||||
"readOnly": true,
|
"target": "Account",
|
||||||
"required": true
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "fiscalYearStart",
|
"label": "Round Off Account",
|
||||||
"label": "Fiscal Year Start Date",
|
"fieldname": "roundOffAccount",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Link",
|
||||||
"required": true
|
"target": "Account",
|
||||||
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "fiscalYearEnd",
|
"label": "Discount Account",
|
||||||
"label": "Fiscal Year End Date",
|
"fieldname": "discountAccount",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Link",
|
||||||
"required": true
|
"target": "Account",
|
||||||
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "enableDiscounting",
|
"fieldname": "enableDiscounting",
|
||||||
"label": "Enable Discount Accounting",
|
"label": "Enable Discount Accounting",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": false
|
"default": false,
|
||||||
},
|
"section": "Feature Flags"
|
||||||
{
|
|
||||||
"fieldname": "discountAccount",
|
|
||||||
"label": "Discount Account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"target": "Account"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "enableInventory",
|
"fieldname": "enableInventory",
|
||||||
"label": "Enable Inventory",
|
"label": "Enable Inventory",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": false
|
"default": false,
|
||||||
|
"section": "Feature Flags"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearStart",
|
||||||
|
"label": "Fiscal Year Start Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": true,
|
||||||
|
"section": "Fiscal Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "fiscalYearEnd",
|
||||||
|
"label": "Fiscal Year End Date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"required": true,
|
||||||
|
"section": "Fiscal Year"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "setupComplete",
|
"fieldname": "setupComplete",
|
||||||
"label": "Setup Complete",
|
"label": "Setup Complete",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": false
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quickEditFields": [
|
"quickEditFields": [
|
||||||
|
@ -9,73 +9,80 @@
|
|||||||
"label": "Sales Invoice Number Series",
|
"label": "Sales Invoice Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchaseInvoiceNumberSeries",
|
"fieldname": "purchaseInvoiceNumberSeries",
|
||||||
"label": "Purchase Invoice Number Series",
|
"label": "Purchase Invoice Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "journalEntryNumberSeries",
|
"fieldname": "journalEntryNumberSeries",
|
||||||
"label": "Journal Entry Number Series",
|
"label": "Journal Entry Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "paymentNumberSeries",
|
"fieldname": "paymentNumberSeries",
|
||||||
"label": "Payment Number Series",
|
"label": "Payment Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "stockMovementNumberSeries",
|
"fieldname": "stockMovementNumberSeries",
|
||||||
"label": "Stock Movement Number Series",
|
"label": "Stock Movement Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "shipmentNumberSeries",
|
"fieldname": "shipmentNumberSeries",
|
||||||
"label": "Shipment Number Series",
|
"label": "Shipment Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchaseReceiptNumberSeries",
|
"fieldname": "purchaseReceiptNumberSeries",
|
||||||
"label": "Purchase Receipt Number Series",
|
"label": "Purchase Receipt Number Series",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "NumberSeries",
|
"target": "NumberSeries",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "salesInvoiceTerms",
|
"fieldname": "salesInvoiceTerms",
|
||||||
"label": "Sales Invoice Terms",
|
"label": "Sales Invoice Terms",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"target": "NumberSeries"
|
"section": "Terms"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchaseInvoiceTerms",
|
"fieldname": "purchaseInvoiceTerms",
|
||||||
"label": "Purchase Invoice Terms",
|
"label": "Purchase Invoice Terms",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"target": "NumberSeries"
|
"section": "Terms"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "shipmentTerms",
|
"fieldname": "shipmentTerms",
|
||||||
"label": "Shipment Terms",
|
"label": "Shipment Terms",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"target": "NumberSeries"
|
"section": "Terms"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "purchaseReceiptTerms",
|
"fieldname": "purchaseReceiptTerms",
|
||||||
"label": "Purchase Receipt Terms",
|
"label": "Purchase Receipt Terms",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"target": "NumberSeries"
|
"section": "Terms"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -6,46 +6,36 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "logo",
|
"fieldname": "logo",
|
||||||
"label": "Logo",
|
"label": "Logo",
|
||||||
"fieldtype": "AttachImage"
|
"fieldtype": "AttachImage",
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "companyName",
|
"fieldname": "companyName",
|
||||||
"label": "Company Name",
|
"label": "Company Name",
|
||||||
"fieldtype": "Data"
|
"fieldtype": "Data",
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "email",
|
"fieldname": "email",
|
||||||
"label": "Email",
|
"label": "Email",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"placeholder": "john@doe.com"
|
"placeholder": "john@doe.com",
|
||||||
},
|
"section": "Contacts"
|
||||||
{
|
|
||||||
"fieldname": "displayLogo",
|
|
||||||
"label": "Display Logo in Invoice",
|
|
||||||
"fieldtype": "Check"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "displayTaxInvoice",
|
|
||||||
"label": "Display Tax Invoice",
|
|
||||||
"fieldtype": "Check"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "displayBatch",
|
|
||||||
"label": "Display Batch",
|
|
||||||
"fieldtype": "Check"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "phone",
|
"fieldname": "phone",
|
||||||
"label": "Phone",
|
"label": "Phone",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"placeholder": "9888900000"
|
"placeholder": "9888900000",
|
||||||
|
"section": "Contacts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "address",
|
"fieldname": "address",
|
||||||
"label": "Address",
|
"label": "Address",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "Address",
|
"target": "Address",
|
||||||
"inline": true
|
"inline": true,
|
||||||
|
"section": "Contacts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "template",
|
"fieldname": "template",
|
||||||
@ -66,7 +56,8 @@
|
|||||||
"label": "Business"
|
"label": "Business"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": "Basic"
|
"default": "Basic",
|
||||||
|
"section": "Customizations"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "color",
|
"fieldname": "color",
|
||||||
@ -115,7 +106,8 @@
|
|||||||
"label": "Black",
|
"label": "Black",
|
||||||
"value": "#112B42"
|
"value": "#112B42"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"section": "Customizations"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "font",
|
"fieldname": "font",
|
||||||
@ -136,7 +128,26 @@
|
|||||||
"label": "Courier"
|
"label": "Courier"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": "Arial"
|
"default": "Arial",
|
||||||
|
"section": "Customizations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "displayLogo",
|
||||||
|
"label": "Display Logo in Invoice",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"section": "Customizations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "displayTaxInvoice",
|
||||||
|
"label": "Display Tax Invoice",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"section": "Customizations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "displayBatch",
|
||||||
|
"label": "Display Batch",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"section": "Customizations"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quickEditFields": [
|
"quickEditFields": [
|
||||||
|
@ -19,47 +19,55 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": "FIFO",
|
"default": "FIFO",
|
||||||
"required": true
|
"required": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "defaultLocation",
|
"fieldname": "defaultLocation",
|
||||||
"label": "Default Location",
|
"label": "Default Location",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "Location",
|
"target": "Location",
|
||||||
"create": true
|
"create": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "stockInHand",
|
"fieldname": "stockInHand",
|
||||||
"label": "Stock In Hand Acc.",
|
"label": "Stock In Hand Acc.",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "Account"
|
"target": "Account",
|
||||||
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "stockReceivedButNotBilled",
|
"fieldname": "stockReceivedButNotBilled",
|
||||||
"label": "Stock Received But Not Billed Acc.",
|
"label": "Stock Received But Not Billed Acc.",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "Account"
|
"target": "Account",
|
||||||
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "costOfGoodsSold",
|
"fieldname": "costOfGoodsSold",
|
||||||
"label": "Cost Of Goods Sold Acc.",
|
"label": "Cost Of Goods Sold Acc.",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"target": "Account"
|
"target": "Account",
|
||||||
|
"section": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "enableBarcodes",
|
"fieldname": "enableBarcodes",
|
||||||
"label": "Enable Barcodes",
|
"label": "Enable Barcodes",
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check",
|
||||||
|
"section": "Feature Flags"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "enableBatches",
|
"fieldname": "enableBatches",
|
||||||
"label": "Enable Batches",
|
"label": "Enable Batches",
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check",
|
||||||
|
"section": "Feature Flags"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "enableUomConversions",
|
"fieldname": "enableUomConversions",
|
||||||
"label": "Enable UOM Conversion",
|
"label": "Enable UOM Conversion",
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check",
|
||||||
|
"section": "Feature Flags"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,23 @@
|
|||||||
"default": "MMM d, y",
|
"default": "MMM d, y",
|
||||||
"required": true,
|
"required": true,
|
||||||
"allowCustom": true,
|
"allowCustom": true,
|
||||||
"description": "Sets the app-wide date display format."
|
"description": "Sets the app-wide date display format.",
|
||||||
|
"section": "Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "hideGetStarted",
|
||||||
|
"label": "Hide Get Started",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"default": false,
|
||||||
|
"description": "Hides the Get Started section from the sidebar. Change will be visible on restart or refreshing the app.",
|
||||||
|
"section": "Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "version",
|
||||||
|
"label": "Version",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"readOnly": true,
|
||||||
|
"section": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "locale",
|
"fieldname": "locale",
|
||||||
@ -54,7 +70,8 @@
|
|||||||
"default": "en-IN",
|
"default": "en-IN",
|
||||||
"required": true,
|
"required": true,
|
||||||
"allowCustom": true,
|
"allowCustom": true,
|
||||||
"description": "Set the local code. This is used for number formatting."
|
"description": "Set the local code. This is used for number formatting.",
|
||||||
|
"section": "Number Display"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "displayPrecision",
|
"fieldname": "displayPrecision",
|
||||||
@ -64,29 +81,8 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"minvalue": 0,
|
"minvalue": 0,
|
||||||
"maxvalue": 9,
|
"maxvalue": 9,
|
||||||
"description": "Sets how many digits are shown after the decimal point."
|
"description": "Sets how many digits are shown after the decimal point.",
|
||||||
},
|
"section": "Number Display"
|
||||||
{
|
|
||||||
"fieldname": "internalPrecision",
|
|
||||||
"label": "Internal Precision",
|
|
||||||
"fieldtype": "Int",
|
|
||||||
"minvalue": 0,
|
|
||||||
"default": 11,
|
|
||||||
"description": "Sets the internal precision used for monetary calculations. Above 6 should be sufficient for most currencies."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "hideGetStarted",
|
|
||||||
"label": "Hide Get Started",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"default": false,
|
|
||||||
"description": "Hides the Get Started section from the sidebar. Change will be visible on restart or refreshing the app."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "countryCode",
|
|
||||||
"label": "Country Code",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"default": "in",
|
|
||||||
"description": "Country code used to initialize regional settings."
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
@ -94,19 +90,32 @@
|
|||||||
"fieldtype": "AutoComplete",
|
"fieldtype": "AutoComplete",
|
||||||
"default": "INR",
|
"default": "INR",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"required": true
|
"required": true,
|
||||||
|
"section": "Number Display"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "version",
|
"fieldname": "internalPrecision",
|
||||||
"label": "Version",
|
"label": "Internal Precision",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"minvalue": 0,
|
||||||
|
"default": 11,
|
||||||
|
"description": "Sets the internal precision used for monetary calculations. Above 6 should be sufficient for most currencies.",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "countryCode",
|
||||||
|
"label": "Country Code",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"readOnly": true
|
"default": "in",
|
||||||
|
"description": "Country code used to initialize regional settings.",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "instanceId",
|
"fieldname": "instanceId",
|
||||||
"label": "Instance Id",
|
"label": "Instance Id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"readOnly": true
|
"readOnly": true,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quickEditFields": [
|
"quickEditFields": [
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
"fieldname": "gstin",
|
"fieldname": "gstin",
|
||||||
"label": "GSTIN",
|
"label": "GSTIN",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"placeholder": "27AAAAA0000A1Z5"
|
"placeholder": "27AAAAA0000A1Z5",
|
||||||
|
"section": "Default"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quickEditFields": [
|
"quickEditFields": [
|
||||||
|
@ -112,6 +112,8 @@ import FormHeader from 'src/components/FormHeader.vue';
|
|||||||
import StatusBadge from 'src/components/StatusBadge.vue';
|
import StatusBadge from 'src/components/StatusBadge.vue';
|
||||||
import { handleErrorWithDialog } from 'src/errorHandling';
|
import { handleErrorWithDialog } from 'src/errorHandling';
|
||||||
import { getErrorMessage } from 'src/utils';
|
import { getErrorMessage } from 'src/utils';
|
||||||
|
import { docsPathMap } from 'src/utils/misc';
|
||||||
|
import { docsPathRef, focusedDocsRef } from 'src/utils/refs';
|
||||||
import { ActionGroup, UIGroupedFields } from 'src/utils/types';
|
import { ActionGroup, UIGroupedFields } from 'src/utils/types';
|
||||||
import {
|
import {
|
||||||
getFieldsGroupedByTabAndSection,
|
getFieldsGroupedByTabAndSection,
|
||||||
@ -155,8 +157,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await this.setDoc();
|
await this.setDoc();
|
||||||
|
focusedDocsRef.add(this.docOrNull);
|
||||||
this.updateGroupedFields();
|
this.updateGroupedFields();
|
||||||
},
|
},
|
||||||
|
activated(): void {
|
||||||
|
docsPathRef.value = docsPathMap[this.schemaName] ?? '';
|
||||||
|
focusedDocsRef.add(this.docOrNull);
|
||||||
|
},
|
||||||
|
deactivated(): void {
|
||||||
|
docsPathRef.value = '';
|
||||||
|
focusedDocsRef.add(this.docOrNull);
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hasDoc(): boolean {
|
hasDoc(): boolean {
|
||||||
return !!this.docOrNull;
|
return !!this.docOrNull;
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
<div
|
<div
|
||||||
v-for="field of fields"
|
v-for="field of fields"
|
||||||
:key="field.fieldname"
|
:key="field.fieldname"
|
||||||
:class="field.fieldtype === 'Table' ? 'col-span-2 text-base' : ''"
|
:class="[
|
||||||
class="mb-auto"
|
field.fieldtype === 'Table' ? 'col-span-2 text-base' : '',
|
||||||
|
field.fieldtype === 'Check' ? 'mt-auto' : 'mb-auto',
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<FormControl
|
<FormControl
|
||||||
:ref="field.fieldname === 'name' ? 'nameField' : 'fields'"
|
:ref="field.fieldname === 'name' ? 'nameField' : 'fields'"
|
||||||
|
@ -338,7 +338,6 @@ export default {
|
|||||||
LinkedEntryWidget,
|
LinkedEntryWidget,
|
||||||
Barcode,
|
Barcode,
|
||||||
},
|
},
|
||||||
inject: ['shortcuts'],
|
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
schemaName: this.schemaName,
|
schemaName: this.schemaName,
|
||||||
|
@ -132,7 +132,6 @@ export default {
|
|||||||
DropdownWithActions,
|
DropdownWithActions,
|
||||||
},
|
},
|
||||||
emits: ['close'],
|
emits: ['close'],
|
||||||
inject: ['shortcuts'],
|
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
schemaName: this.schemaName,
|
schemaName: this.schemaName,
|
||||||
|
@ -1,191 +1,268 @@
|
|||||||
<template>
|
<template>
|
||||||
<FormContainer :title="t`Settings`" :searchborder="false">
|
<FormContainer>
|
||||||
|
<template #header>
|
||||||
|
<Button v-if="canSave" type="primary" @click="sync">
|
||||||
|
{{ t`Save` }}
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<!-- Icon Tab Bar -->
|
<FormHeader
|
||||||
<div class="flex m-4 mb-0 gap-8">
|
:form-title="tabLabels[activeTab] ?? ''"
|
||||||
<button
|
:form-sub-title="t`Settings`"
|
||||||
v-for="(tab, i) in tabs"
|
class="sticky top-0 bg-white border-b"
|
||||||
:key="tab.label"
|
>
|
||||||
class="
|
</FormHeader>
|
||||||
hover:bg-white
|
<!-- Section Container -->
|
||||||
flex flex-col
|
|
||||||
items-center
|
<div class="overflow-auto custom-scroll" v-if="doc">
|
||||||
justify-center
|
<CommonFormSection
|
||||||
cursor-pointer
|
v-for="([name, fields], idx) in activeGroup.entries()"
|
||||||
text-sm
|
@editrow="(doc: Doc) => toggleQuickEditDoc(doc)"
|
||||||
"
|
:key="name + idx"
|
||||||
:class="
|
ref="section"
|
||||||
i === activeTab &&
|
class="p-4"
|
||||||
'text-blue-500 font-semibold border-b-2 border-blue-500'
|
:class="idx !== 0 && activeGroup.size > 1 ? 'border-t' : ''"
|
||||||
"
|
:show-title="activeGroup.size > 1 && name !== t`Default`"
|
||||||
:style="{
|
:title="name"
|
||||||
paddingBottom: i === activeTab ? 'calc(1rem - 2px)' : '1rem',
|
:fields="fields"
|
||||||
}"
|
:doc="doc"
|
||||||
@click="activeTab = i"
|
:errors="errors"
|
||||||
>
|
@value-change="onValueChange"
|
||||||
{{ tab.label }}
|
/>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Component -->
|
<!-- Tab Bar -->
|
||||||
<div class="flex-1 overflow-y-auto custom-scroll">
|
<div
|
||||||
<component
|
class="
|
||||||
:is="tabs[activeTab].component"
|
mt-auto
|
||||||
:schema-name="tabs[activeTab].schemaName"
|
px-4
|
||||||
@change="handleChange"
|
pb-4
|
||||||
/>
|
flex
|
||||||
|
gap-8
|
||||||
|
border-t
|
||||||
|
flex-shrink-0
|
||||||
|
sticky
|
||||||
|
bottom-0
|
||||||
|
bg-white
|
||||||
|
"
|
||||||
|
v-if="groupedFields && groupedFields.size > 1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="key of groupedFields.keys()"
|
||||||
|
:key="key"
|
||||||
|
@click="activeTab = key"
|
||||||
|
class="text-sm cursor-pointer"
|
||||||
|
:class="
|
||||||
|
key === activeTab
|
||||||
|
? 'text-blue-500 font-semibold border-t-2 border-blue-500'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
:style="{
|
||||||
|
paddingTop: key === activeTab ? 'calc(1rem - 2px)' : '1rem',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ tabLabels[key] }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script lang="ts">
|
||||||
import { ipcRenderer } from 'electron';
|
import { DocValue } from 'fyo/core/types';
|
||||||
import { t } from 'fyo';
|
import { Doc } from 'fyo/model/doc';
|
||||||
|
import { ValidationError } from 'fyo/utils/errors';
|
||||||
|
import { ModelNameEnum } from 'models/types';
|
||||||
|
import { Field, Schema } from 'schemas/types';
|
||||||
import Button from 'src/components/Button.vue';
|
import Button from 'src/components/Button.vue';
|
||||||
import FormContainer from 'src/components/FormContainer.vue';
|
import FormContainer from 'src/components/FormContainer.vue';
|
||||||
import Icon from 'src/components/Icon.vue';
|
import FormHeader from 'src/components/FormHeader.vue';
|
||||||
import PageHeader from 'src/components/PageHeader.vue';
|
import { handleErrorWithDialog } from 'src/errorHandling';
|
||||||
import Row from 'src/components/Row.vue';
|
import { getErrorMessage } from 'src/utils';
|
||||||
import StatusBadge from 'src/components/StatusBadge.vue';
|
import { evaluateHidden } from 'src/utils/doc';
|
||||||
import { fyo } from 'src/initFyo';
|
import { reloadWindow } from 'src/utils/ipcCalls';
|
||||||
import { docsPathMap } from 'src/utils/misc';
|
import { docsPathMap } from 'src/utils/misc';
|
||||||
import { docsPathRef } from 'src/utils/refs';
|
import { docsPathRef } from 'src/utils/refs';
|
||||||
|
import { UIGroupedFields } from 'src/utils/types';
|
||||||
import { showToast } from 'src/utils/ui';
|
import { showToast } from 'src/utils/ui';
|
||||||
import { IPC_MESSAGES } from 'utils/messages';
|
import { computed, defineComponent, nextTick } from 'vue';
|
||||||
import { h, markRaw } from 'vue';
|
import CommonFormSection from '../CommonForm/CommonFormSection.vue';
|
||||||
import TabBase from './TabBase.vue';
|
|
||||||
import TabGeneral from './TabGeneral.vue';
|
|
||||||
import TabInvoice from './TabInvoice.vue';
|
|
||||||
import TabSystem from './TabSystem.vue';
|
|
||||||
export default {
|
|
||||||
name: 'Settings',
|
|
||||||
components: {
|
|
||||||
PageHeader,
|
|
||||||
StatusBadge,
|
|
||||||
Button,
|
|
||||||
Row,
|
|
||||||
FormContainer,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
const hasInventory = !!fyo.singles.AccountingSettings?.enableInventory;
|
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: { FormContainer, Button, FormHeader, CommonFormSection },
|
||||||
|
data() {
|
||||||
return {
|
return {
|
||||||
activeTab: 0,
|
errors: {},
|
||||||
updated: false,
|
canSave: false,
|
||||||
fieldsChanged: [],
|
activeTab: ModelNameEnum.AccountingSettings,
|
||||||
tabs: [
|
groupedFields: null,
|
||||||
{
|
quickEditDoc: null,
|
||||||
key: 'Invoice',
|
} as {
|
||||||
label: t`Invoice`,
|
errors: Record<string, string>;
|
||||||
schemaName: 'PrintSettings',
|
canSave: boolean;
|
||||||
component: markRaw(TabInvoice),
|
activeTab: string;
|
||||||
},
|
groupedFields: null | UIGroupedFields;
|
||||||
{
|
quickEditDoc: null | Doc;
|
||||||
key: 'General',
|
|
||||||
label: t`General`,
|
|
||||||
schemaName: 'AccountingSettings',
|
|
||||||
component: markRaw(TabGeneral),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'Defaults',
|
|
||||||
label: t`Defaults`,
|
|
||||||
schemaName: 'Defaults',
|
|
||||||
component: markRaw(TabBase),
|
|
||||||
},
|
|
||||||
...(hasInventory
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: 'Inventory',
|
|
||||||
label: t`Inventory`,
|
|
||||||
schemaName: 'InventorySettings',
|
|
||||||
component: markRaw(TabBase),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
key: 'System',
|
|
||||||
label: t`System`,
|
|
||||||
schemaName: 'SystemSettings',
|
|
||||||
component: markRaw(TabSystem),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
activated() {
|
provide() {
|
||||||
this.setActiveTab();
|
return { doc: computed(() => this.doc) };
|
||||||
docsPathRef.value = docsPathMap.Settings;
|
|
||||||
},
|
},
|
||||||
deactivated() {
|
mounted() {
|
||||||
|
if (this.fyo.store.isDevelopment) {
|
||||||
|
// @ts-ignore
|
||||||
|
window.settings = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
activated(): void {
|
||||||
|
docsPathRef.value = docsPathMap.Settings ?? '';
|
||||||
|
},
|
||||||
|
deactivated(): void {
|
||||||
docsPathRef.value = '';
|
docsPathRef.value = '';
|
||||||
if (this.fieldsChanged.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const shouleShowReload = this.fieldsChanged
|
|
||||||
.map(({ fieldname }) => fieldname)
|
|
||||||
.some((f) => {
|
|
||||||
if (f.startsWith('enable')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f === 'displayPrecision') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f === 'hideGetStarted') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (shouleShowReload) {
|
|
||||||
this.showReloadToast();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showReloadToast() {
|
async sync(): Promise<void> {
|
||||||
showToast({
|
const syncableDocs = this.schemas
|
||||||
message: t`Settings changes will be visible on reload`,
|
.map(({ name }) => this.fyo.singles[name])
|
||||||
actionText: t`Reload App`,
|
.filter((doc) => doc?.canSave) as Doc[];
|
||||||
type: 'info',
|
|
||||||
action: async () => {
|
for (const doc of syncableDocs) {
|
||||||
ipcRenderer.send(IPC_MESSAGES.RELOAD_MAIN_WINDOW);
|
await this.syncDoc(doc);
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleChange(df, newValue, oldValue) {
|
|
||||||
if (!df) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fieldsChanged.push(df);
|
this.update();
|
||||||
|
await showToast({
|
||||||
|
message: this.t`Changes will be visible on reload`,
|
||||||
|
actionText: this.t`Reload App`,
|
||||||
|
type: 'info',
|
||||||
|
action: reloadWindow,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
setActiveTab() {
|
async syncDoc(doc: Doc): Promise<void> {
|
||||||
const { tab } = this.$route.query;
|
try {
|
||||||
const index = this.tabs.findIndex((i) => i.key === tab);
|
await doc.sync();
|
||||||
if (index !== -1) {
|
this.updateGroupedFields();
|
||||||
this.activeTab = index;
|
} catch (err) {
|
||||||
} else {
|
if (!(err instanceof Error)) {
|
||||||
this.activeTab = 0;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await handleErrorWithDialog(err, doc);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getIconComponent(tab) {
|
async toggleQuickEditDoc(doc: Doc | null): Promise<void> {
|
||||||
return {
|
if (this.quickEditDoc && doc) {
|
||||||
render() {
|
this.quickEditDoc = null;
|
||||||
return h(Icon, {
|
await nextTick();
|
||||||
class: 'w-6 h-6',
|
}
|
||||||
...Object.assign(
|
|
||||||
{
|
this.quickEditDoc = doc;
|
||||||
name: tab.icon,
|
},
|
||||||
size: '24',
|
async onValueChange(field: Field, value: DocValue): Promise<void> {
|
||||||
},
|
const { fieldname } = field;
|
||||||
this.$attrs
|
delete this.errors[fieldname];
|
||||||
),
|
|
||||||
});
|
try {
|
||||||
},
|
await this.doc?.set(fieldname, value);
|
||||||
};
|
} catch (err) {
|
||||||
|
if (!(err instanceof Error)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.errors[fieldname] = getErrorMessage(err, this.doc ?? undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
update(): void {
|
||||||
|
this.updateCanSave();
|
||||||
|
this.updateGroupedFields();
|
||||||
|
},
|
||||||
|
updateCanSave(): void {
|
||||||
|
this.canSave = this.schemas
|
||||||
|
.map(({ name }) => this.fyo.singles[name]?.canSave)
|
||||||
|
.some(Boolean);
|
||||||
|
},
|
||||||
|
updateGroupedFields(): void {
|
||||||
|
const grouped: UIGroupedFields = new Map();
|
||||||
|
const fields: Field[] = this.schemas.map((s) => s.fields).flat();
|
||||||
|
|
||||||
|
for (const field of fields) {
|
||||||
|
const schemaName = field.schemaName!;
|
||||||
|
if (!grouped.has(schemaName)) {
|
||||||
|
grouped.set(schemaName, new Map());
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabbed = grouped.get(schemaName)!;
|
||||||
|
const section = field.section ?? this.t`Miscellaneous`;
|
||||||
|
if (!tabbed.has(section)) {
|
||||||
|
tabbed.set(section, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.meta) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = this.fyo.singles[schemaName];
|
||||||
|
if (evaluateHidden(field, doc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabbed.get(section)!.push(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.groupedFields = grouped;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
computed: {
|
||||||
|
doc(): Doc | null {
|
||||||
|
const doc = this.fyo.singles[this.activeTab];
|
||||||
|
if (!doc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
},
|
||||||
|
tabLabels(): Record<string, string> {
|
||||||
|
return {
|
||||||
|
[ModelNameEnum.AccountingSettings]: this.t`General`,
|
||||||
|
[ModelNameEnum.PrintSettings]: this.t`Print`,
|
||||||
|
[ModelNameEnum.InventorySettings]: this.t`Inventory`,
|
||||||
|
[ModelNameEnum.Defaults]: this.t`Defaults`,
|
||||||
|
[ModelNameEnum.SystemSettings]: this.t`System`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
schemas(): Schema[] {
|
||||||
|
const enableInventory =
|
||||||
|
!!this.fyo.singles.AccountingSettings?.enableInventory;
|
||||||
|
|
||||||
|
return [
|
||||||
|
ModelNameEnum.AccountingSettings,
|
||||||
|
ModelNameEnum.InventorySettings,
|
||||||
|
ModelNameEnum.Defaults,
|
||||||
|
ModelNameEnum.PrintSettings,
|
||||||
|
ModelNameEnum.SystemSettings,
|
||||||
|
]
|
||||||
|
.filter((s) =>
|
||||||
|
s === ModelNameEnum.InventorySettings ? enableInventory : true
|
||||||
|
)
|
||||||
|
.map((s) => this.fyo.schemaMap[s]!);
|
||||||
|
},
|
||||||
|
activeGroup(): Map<string, Field[]> {
|
||||||
|
if (!this.groupedFields) {
|
||||||
|
return new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
const group = this.groupedFields.get(this.activeTab);
|
||||||
|
if (!group) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`Tab group ${this.activeTab} has no value set`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<TwoColumnForm
|
|
||||||
v-if="doc"
|
|
||||||
:doc="doc"
|
|
||||||
:fields="fields"
|
|
||||||
:autosave="true"
|
|
||||||
:emit-change="true"
|
|
||||||
@change="(...args:unknown[])=>$emit('change', ...args)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import { Doc } from 'fyo/model/doc';
|
|
||||||
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'TabGeneral',
|
|
||||||
emits: ['change'],
|
|
||||||
props: { schemaName: String },
|
|
||||||
components: {
|
|
||||||
TwoColumnForm,
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
await this.setDoc();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
async schemaName() {
|
|
||||||
await this.setDoc();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async setDoc() {
|
|
||||||
if (this.doc && this.schemaName === this.doc.schemaName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.schemaName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.doc = await this.fyo.doc.getDoc(this.schemaName, this.schemaName, {
|
|
||||||
skipDocumentCache: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
doc: undefined,
|
|
||||||
} as { doc?: Doc };
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
fields() {
|
|
||||||
return this.doc?.schema.fields;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,49 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { Field } from 'schemas/types';
|
|
||||||
import { fyo } from 'src/initFyo';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import TabBase from './TabBase.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
extends: TabBase,
|
|
||||||
name: 'TabGeneral',
|
|
||||||
async mounted() {
|
|
||||||
this.doc = await fyo.doc.getDoc(
|
|
||||||
'AccountingSettings',
|
|
||||||
'AccountingSettings',
|
|
||||||
{
|
|
||||||
skipDocumentCache: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
fields() {
|
|
||||||
const fields = [
|
|
||||||
'fullname',
|
|
||||||
'companyName',
|
|
||||||
'country',
|
|
||||||
'bankName',
|
|
||||||
'currency',
|
|
||||||
'fiscalYearStart',
|
|
||||||
'fiscalYearEnd',
|
|
||||||
'writeOffAccount',
|
|
||||||
'roundOffAccount',
|
|
||||||
'enableDiscounting',
|
|
||||||
'enableInventory',
|
|
||||||
];
|
|
||||||
|
|
||||||
if (this.doc?.enableDiscounting) {
|
|
||||||
fields.push('discountAccount');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fyo.singles.SystemSettings?.countryCode === 'in') {
|
|
||||||
fields.push('gstin');
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields
|
|
||||||
.map((fieldname) => fyo.getField('AccountingSettings', fieldname))
|
|
||||||
.filter(Boolean) as Field[];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,101 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-if="doc" class="pb-4">
|
|
||||||
<hr />
|
|
||||||
<div class="flex items-center gap-4 p-4">
|
|
||||||
<FormControl
|
|
||||||
:df="getField('logo')"
|
|
||||||
:value="doc.logo"
|
|
||||||
@change="
|
|
||||||
(value) => {
|
|
||||||
doc.setAndSync('logo', value);
|
|
||||||
forwardChangeEvent(getField('logo'));
|
|
||||||
}
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<span
|
|
||||||
class="bg-transparent font-semibold text-xl text-gray-900 px-3 py-2"
|
|
||||||
>
|
|
||||||
{{ companyName }}
|
|
||||||
</span>
|
|
||||||
<span class="text-lg text-gray-800 px-3 py-2">
|
|
||||||
{{ doc.email }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<TwoColumnForm
|
|
||||||
:doc="doc"
|
|
||||||
:fields="fields"
|
|
||||||
:autosave="true"
|
|
||||||
:emit-change="true"
|
|
||||||
@change="forwardChangeEvent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { ipcRenderer } from 'electron';
|
|
||||||
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
|
|
||||||
import { fyo } from 'src/initFyo';
|
|
||||||
import { IPC_ACTIONS } from 'utils/messages';
|
|
||||||
import FormControl from '../../components/Controls/FormControl.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'TabInvoice',
|
|
||||||
components: {
|
|
||||||
TwoColumnForm,
|
|
||||||
FormControl,
|
|
||||||
},
|
|
||||||
emits: ['change'],
|
|
||||||
provide() {
|
|
||||||
return {
|
|
||||||
schemaName: 'PrintSettings',
|
|
||||||
name: 'PrintSettings',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
companyName: null,
|
|
||||||
doc: null,
|
|
||||||
showEdit: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
this.doc = await fyo.doc.getDoc('PrintSettings');
|
|
||||||
this.companyName = (await fyo.doc.getDoc('AccountingSettings')).companyName;
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
fields() {
|
|
||||||
const fields = ['template', 'color', 'font', 'email', 'phone', 'address'];
|
|
||||||
|
|
||||||
if (this.doc.logo) {
|
|
||||||
fields.unshift('displayLogo');
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields.map((field) => this.getField(field));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getField(fieldname) {
|
|
||||||
return fyo.getField('PrintSettings', fieldname);
|
|
||||||
},
|
|
||||||
async openFileSelector() {
|
|
||||||
const options = {
|
|
||||||
title: t`Select Logo`,
|
|
||||||
properties: ['openFile'],
|
|
||||||
filters: [{ name: 'Invoice Logo', extensions: ['png', 'jpg', 'svg'] }],
|
|
||||||
};
|
|
||||||
const { filePaths } = await ipcRenderer.invoke(
|
|
||||||
IPC_ACTIONS.GET_OPEN_FILEPATH,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
if (filePaths[0] !== undefined) {
|
|
||||||
this.doc.set('logo', `file://${files[0]}`);
|
|
||||||
this.doc.update;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
forwardChangeEvent(...args) {
|
|
||||||
this.$emit('change', ...args);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,58 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex flex-col justify-between h-full">
|
|
||||||
<TwoColumnForm
|
|
||||||
v-if="doc"
|
|
||||||
:doc="doc"
|
|
||||||
:fields="fields"
|
|
||||||
:autosave="true"
|
|
||||||
:emit-change="true"
|
|
||||||
@change="forwardChangeEvent"
|
|
||||||
/>
|
|
||||||
<div class="flex p-4 justify-between">
|
|
||||||
<LanguageSelector class="text-sm w-28" />
|
|
||||||
<p class="mt-auto text-gray-600 text-base select-none">
|
|
||||||
{{ `v${fyo.store.appVersion}` }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { ConfigKeys } from 'fyo/core/types';
|
|
||||||
import { ModelNameEnum } from 'models/types';
|
|
||||||
import LanguageSelector from 'src/components/Controls/LanguageSelector.vue';
|
|
||||||
import TwoColumnForm from 'src/components/TwoColumnForm';
|
|
||||||
import { fyo } from 'src/initFyo';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'TabSystem',
|
|
||||||
components: {
|
|
||||||
TwoColumnForm,
|
|
||||||
LanguageSelector,
|
|
||||||
},
|
|
||||||
emits: ['change'],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
doc: null,
|
|
||||||
telemetry: '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
this.doc = fyo.singles.SystemSettings;
|
|
||||||
this.companyName = fyo.singles.AccountingSettings.companyName;
|
|
||||||
this.telemetry = fyo.config.get(ConfigKeys.Telemetry);
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
fields() {
|
|
||||||
return fyo.schemaMap.SystemSettings.quickEditFields.map((f) =>
|
|
||||||
fyo.getField(ModelNameEnum.SystemSettings, f)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
forwardChangeEvent(...args) {
|
|
||||||
this.$emit('change', ...args);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -10,6 +10,10 @@ import { SelectFileOptions, SelectFileReturn } from 'utils/types';
|
|||||||
import { setLanguageMap } from './language';
|
import { setLanguageMap } from './language';
|
||||||
import { showMessageDialog, showToast } from './ui';
|
import { showMessageDialog, showToast } from './ui';
|
||||||
|
|
||||||
|
export function reloadWindow() {
|
||||||
|
return ipcRenderer.send(IPC_MESSAGES.RELOAD_MAIN_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
export async function selectFile(
|
export async function selectFile(
|
||||||
options: SelectFileOptions
|
options: SelectFileOptions
|
||||||
): Promise<SelectFileReturn> {
|
): Promise<SelectFileReturn> {
|
||||||
|
@ -2,7 +2,8 @@ import { ipcRenderer } from 'electron';
|
|||||||
import { DEFAULT_LANGUAGE } from 'fyo/utils/consts';
|
import { DEFAULT_LANGUAGE } from 'fyo/utils/consts';
|
||||||
import { setLanguageMapOnTranslationString } from 'fyo/utils/translation';
|
import { setLanguageMapOnTranslationString } from 'fyo/utils/translation';
|
||||||
import { fyo } from 'src/initFyo';
|
import { fyo } from 'src/initFyo';
|
||||||
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
import { IPC_ACTIONS } from 'utils/messages';
|
||||||
|
import { reloadWindow } from './ipcCalls';
|
||||||
import { systemLanguageRef } from './refs';
|
import { systemLanguageRef } from './refs';
|
||||||
import { showToast } from './ui';
|
import { showToast } from './ui';
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ export async function setLanguageMap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dontReload && success && initLanguage !== oldLanguage) {
|
if (!dontReload && success && initLanguage !== oldLanguage) {
|
||||||
await ipcRenderer.send(IPC_MESSAGES.RELOAD_MAIN_WINDOW);
|
reloadWindow();
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user