2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 23:00:56 +00:00

refactor: Setup wizard and company setup

- Move setup logic into setupCompany.js
- Set setupComplete field in AccountingSettings
- move connectToLocalDatabase in utils
This commit is contained in:
Faris Ansari 2020-01-01 13:41:57 +05:30
parent 69434d53eb
commit 67e9ce094d
9 changed files with 186 additions and 219 deletions

View File

@ -1,6 +1,4 @@
const countryList = Object.keys( const countryList = Object.keys(require('~/fixtures/countryInfo.json')).sort();
require('../../../fixtures/countryInfo.json')
).sort();
module.exports = { module.exports = {
name: 'AccountingSettings', name: 'AccountingSettings',
@ -100,6 +98,13 @@ module.exports = {
required: 1 required: 1
}, },
{
fieldname: 'setupComplete',
label: 'Setup Complete',
fieldtype: 'Check',
default: 0
},
{ {
fieldname: 'autoUpdate', fieldname: 'autoUpdate',
label: 'Auto Update', label: 'Auto Update',

View File

@ -1,5 +1,5 @@
const { DateTime } = require('luxon'); const { DateTime } = require('luxon');
const countryList = require('../../../fixtures/countryInfo.json'); const countryList = require('~/fixtures/countryInfo.json');
module.exports = { module.exports = {
name: 'SetupWizard', name: 'SetupWizard',

View File

@ -4,10 +4,16 @@
v-if="['Windows', 'Linux'].includes(platform)" v-if="['Windows', 'Linux'].includes(platform)"
@close="reloadMainWindowOnSettingsClose" @close="reloadMainWindowOnSettingsClose"
/> />
<Desk class="flex-1" v-if="showDesk" /> <Desk class="flex-1" v-if="activeScreen === 'Desk'" />
<database-selector v-if="showDatabaseSelector" @file="connectToDBFile" /> <DatabaseSelector
<setup-wizard v-if="showSetupWizard" /> v-if="activeScreen === 'DatabaseSelector'"
<Settings v-if="showSettings" /> @database-connect="showSetupWizardOrDesk"
/>
<SetupWizard
v-if="activeScreen === 'SetupWizard'"
@setup-complete="showSetupWizardOrDesk"
/>
<Settings v-if="activeScreen === 'Settings'" />
<portal-target name="popovers" multiple></portal-target> <portal-target name="popovers" multiple></portal-target>
</div> </div>
</template> </template>
@ -22,44 +28,30 @@ import DatabaseSelector from './pages/DatabaseSelector';
import Settings from '@/pages/Settings/Settings.vue'; import Settings from '@/pages/Settings/Settings.vue';
import WindowsTitleBar from '@/components/WindowsTitleBar'; import WindowsTitleBar from '@/components/WindowsTitleBar';
import { remote } from 'electron'; import { remote } from 'electron';
import { connectToLocalDatabase } from '@/utils';
export default { export default {
name: 'App', name: 'App',
data() { data() {
return { return {
showDatabaseSelector: false, activeScreen: null
showDesk: false,
showSetupWizard: false,
showSettings: false
}; };
}, },
watch: { watch: {
showDatabaseSelector(newValue) { activeScreen(value) {
if (newValue) { if (!value) return;
let win = remote.getCurrentWindow(); let size = {
win.setSize(600, 600); Desk: [1200, 907],
win.setResizable(false); DatabaseSelector: [600, 600],
} SetupWizard: [600, 600],
}, Settings: [460, 577]
showSetupWizard(newValue) { }[value];
if (newValue) { let resizable = value === 'Desk';
let win = remote.getCurrentWindow();
win.setSize(600, 600); let win = remote.getCurrentWindow();
win.setResizable(false); if (size.length) {
} win.setSize(...size);
}, win.setResizable(resizable);
showSettings(newValue) {
if (newValue) {
let win = remote.getCurrentWindow();
win.setSize(460, 577);
win.setResizable(false);
}
},
showDesk(newValue) {
if (newValue) {
let win = remote.getCurrentWindow();
win.setSize(1200, 907);
win.setResizable(true);
} }
} }
}, },
@ -70,36 +62,29 @@ export default {
Settings, Settings,
WindowsTitleBar WindowsTitleBar
}, },
mounted() { async mounted() {
if (!localStorage.dbPath) { let dbPath = localStorage.dbPath;
this.showDatabaseSelector = true; if (!dbPath) {
this.activeScreen = 'DatabaseSelector';
} else { } else {
frappe.events.trigger('connect-database', localStorage.dbPath); await connectToLocalDatabase(dbPath);
this.showSetupWizardOrDesk();
} }
frappe.events.on('show-setup-wizard', () => {
this.showSetupWizard = true;
this.showDesk = false;
this.showDatabaseSelector = false;
});
frappe.events.on('show-desk', () => {
if (this.$route.path.startsWith('/settings')) {
this.showSettings = true;
} else {
this.showDesk = true;
this.checkForUpdates();
}
this.showSetupWizard = false;
this.showDatabaseSelector = false;
});
}, },
methods: { methods: {
connectToDBFile(filePath) { showSetupWizardOrDesk() {
frappe.events.trigger('DatabaseSelector:file-selected', filePath); const { setupComplete } = frappe.AccountingSettings;
if (!setupComplete) {
this.activeScreen = 'SetupWizard';
} else if (this.$route.path.startsWith('/settings')) {
this.activeScreen = 'Settings';
} else {
this.activeScreen = 'Desk';
this.checkForUpdates();
}
}, },
reloadMainWindowOnSettingsClose() { reloadMainWindowOnSettingsClose() {
if (this.showSettings) { if (this.activeScreen === 'Settings') {
frappe.events.trigger('reload-main-window'); frappe.events.trigger('reload-main-window');
} }
}, },

View File

@ -1,12 +1,10 @@
// frappejs imports // frappejs imports
import frappe from 'frappejs'; import frappe from 'frappejs';
import SQLite from 'frappejs/backends/sqlite';
import common from 'frappejs/common'; import common from 'frappejs/common';
import coreModels from 'frappejs/models'; import coreModels from 'frappejs/models';
import FeatherIcon from 'frappejs/ui/components/FeatherIcon'; import FeatherIcon from 'frappejs/ui/components/FeatherIcon';
import outsideClickDirective from 'frappejs/ui/plugins/outsideClickDirective'; import outsideClickDirective from 'frappejs/ui/plugins/outsideClickDirective';
import models from '../models'; import models from '../models';
import postStart from '../server/postStart';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
// vue imports // vue imports
@ -23,39 +21,6 @@ import router from './router';
frappe.registerModels(coreModels); frappe.registerModels(coreModels);
frappe.registerModels(models); frappe.registerModels(models);
frappe.fetch = window.fetch.bind(); frappe.fetch = window.fetch.bind();
frappe.events.on('connect-database', async filepath => {
await connectToLocalDatabase(filepath);
const { completed } = await frappe.getSingle('SetupWizard');
if (!completed) {
frappe.events.trigger('show-setup-wizard');
return;
}
const { country } = await frappe.getSingle('AccountingSettings');
if (country === 'India') {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
} else {
frappe.models.Party = require('../models/doctype/Party/Party.js');
}
frappe.events.trigger('show-desk');
});
frappe.events.on('DatabaseSelector:file-selected', async filepath => {
await connectToLocalDatabase(filepath);
localStorage.dbPath = filepath;
const { companyName } = await frappe.getSingle('AccountingSettings');
if (!companyName) {
frappe.events.trigger('show-setup-wizard');
} else {
frappe.events.trigger('show-desk');
}
});
frappe.events.on('reload-main-window', () => { frappe.events.on('reload-main-window', () => {
ipcRenderer.send('reload-main-window'); ipcRenderer.send('reload-main-window');
@ -68,122 +33,6 @@ import router from './router';
} }
}); });
frappe.events.on('SetupWizard:setup-complete', async setupWizardValues => {
const countryList = require('../fixtures/countryInfo.json');
const {
companyLogo,
companyName,
country,
name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd
} = setupWizardValues;
const doc = await frappe.getSingle('AccountingSettings');
await doc.set({
companyName,
country,
fullname: name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd,
currency: countryList[country]['currency']
});
await doc.update();
const printSettings = await frappe.getSingle('PrintSettings');
printSettings.set({
logo: companyLogo,
companyName,
email,
displayLogo: companyLogo ? 1 : 0
});
await printSettings.update();
await setupGlobalCurrencies(countryList);
await setupChartOfAccounts(bankName);
await setupRegionalChanges(country);
await setupWizardValues.set({ completed: 1 });
await setupWizardValues.update();
frappe.events.trigger('show-desk');
});
async function setupGlobalCurrencies(countries) {
const promises = [];
const queue = [];
for (let country of Object.values(countries)) {
const {
currency,
currency_fraction: fraction,
currency_fraction_units: fractionUnits,
smallest_currency_fraction_value: smallestValue,
currency_symbol: symbol,
number_format: numberFormat
} = country;
if (currency) {
const exists = queue.includes(currency);
if (!exists) {
const doc = await frappe.newDoc({
doctype: 'Currency',
name: currency,
fraction,
fractionUnits,
smallestValue,
symbol,
numberFormat: numberFormat || '#,###.##'
});
promises.push(doc.insert());
queue.push(currency);
}
}
}
return Promise.all(promises);
}
async function setupChartOfAccounts(bankName) {
await frappe.call({
method: 'import-coa'
});
const accountDoc = await frappe.newDoc({
doctype: 'Account'
});
Object.assign(accountDoc, {
name: bankName,
rootType: 'Asset',
parentAccount: 'Bank Accounts',
accountType: 'Bank',
isGroup: 0
});
accountDoc.insert();
}
async function setupRegionalChanges(country) {
const generateRegionalTaxes = require('../models/doctype/Tax/RegionalChanges');
await generateRegionalTaxes(country);
if (country === 'India') {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges');
await frappe.db.migrate();
}
}
async function connectToLocalDatabase(filepath) {
frappe.login('Administrator');
frappe.db = new SQLite({
dbPath: filepath
});
await frappe.db.connect();
await frappe.db.migrate();
await postStart();
}
window.frappe = frappe; window.frappe = frappe;
Vue.config.productionTip = false; Vue.config.productionTip = false;

View File

@ -44,18 +44,26 @@
</div> </div>
</template> </template>
<script> <script>
import { createNewDatabase, loadExistingDatabase } from '@/utils'; import {
createNewDatabase,
loadExistingDatabase,
connectToLocalDatabase
} from '@/utils';
export default { export default {
name: 'DatabaseSelector', name: 'DatabaseSelector',
methods: { methods: {
async newDatabase() { async newDatabase() {
let filePath = await createNewDatabase(); let filePath = await createNewDatabase();
this.$emit('file', filePath); this.connectToDatabase(filePath);
}, },
async existingDatabase() { async existingDatabase() {
let filePath = await loadExistingDatabase(); let filePath = await loadExistingDatabase();
this.$emit('file', filePath); this.connectToDatabase(filePath);
},
async connectToDatabase(filePath) {
await connectToLocalDatabase(filePath);
this.$emit('database-connect');
} }
} }
}; };

View File

@ -57,6 +57,7 @@ import frappe from 'frappejs';
import TwoColumnForm from '@/components/TwoColumnForm'; import TwoColumnForm from '@/components/TwoColumnForm';
import FormControl from '@/components/Controls/FormControl'; import FormControl from '@/components/Controls/FormControl';
import Button from '@/components/Button'; import Button from '@/components/Button';
import setupCompany from './setupCompany';
import { handleErrorWithDialog, showMessageDialog } from '@/utils'; import { handleErrorWithDialog, showMessageDialog } from '@/utils';
export default { export default {
@ -104,10 +105,11 @@ export default {
} }
try { try {
this.loading = true; this.loading = true;
frappe.events.trigger('SetupWizard:setup-complete', this.doc); await setupCompany(this.doc);
this.$emit('setup-complete');
} catch (e) { } catch (e) {
this.loading = false; this.loading = false;
console.error(e); handleErrorWithDialog(e, this.doc);
} }
} }
}, },

View File

@ -0,0 +1,102 @@
import frappe from 'frappejs';
import countryList from '~/fixtures/countryInfo.json';
export default async function setupCompany(setupWizardValues) {
const {
companyLogo,
companyName,
country,
name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd
} = setupWizardValues;
const accountingSettings = frappe.AccountingSettings;
await accountingSettings.update({
companyName,
country,
fullname: name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd,
currency: countryList[country]['currency']
});
const printSettings = await frappe.getSingle('PrintSettings');
printSettings.update({
logo: companyLogo,
companyName,
email,
displayLogo: companyLogo ? 1 : 0
});
await setupGlobalCurrencies(countryList);
await setupChartOfAccounts(bankName);
await setupRegionalChanges(country);
await accountingSettings.update({ setupComplete: 1 });
frappe.AccountingSettings = accountingSettings;
}
async function setupGlobalCurrencies(countries) {
const promises = [];
const queue = [];
for (let country of Object.values(countries)) {
const {
currency,
currency_fraction: fraction,
currency_fraction_units: fractionUnits,
smallest_currency_fraction_value: smallestValue,
currency_symbol: symbol,
number_format: numberFormat
} = country;
if (currency) {
const exists = queue.includes(currency);
if (!exists) {
const doc = await frappe.newDoc({
doctype: 'Currency',
name: currency,
fraction,
fractionUnits,
smallestValue,
symbol,
numberFormat: numberFormat || '#,###.##'
});
promises.push(doc.insert());
queue.push(currency);
}
}
}
return Promise.all(promises);
}
async function setupChartOfAccounts(bankName) {
await frappe.call({
method: 'import-coa'
});
const accountDoc = await frappe.newDoc({
doctype: 'Account'
});
Object.assign(accountDoc, {
name: bankName,
rootType: 'Asset',
parentAccount: 'Bank Accounts',
accountType: 'Bank',
isGroup: 0
});
accountDoc.insert();
}
async function setupRegionalChanges(country) {
const generateRegionalTaxes = require('~/models/doctype/Tax/RegionalChanges');
await generateRegionalTaxes(country);
if (country === 'India') {
frappe.models.Party = require('~/models/doctype/Party/RegionalChanges');
await frappe.db.migrate();
}
}

View File

@ -2,6 +2,8 @@ import frappe from 'frappejs';
import fs from 'fs'; import fs from 'fs';
import { _ } from 'frappejs/utils'; import { _ } from 'frappejs/utils';
import { remote, shell } from 'electron'; import { remote, shell } from 'electron';
import SQLite from 'frappejs/backends/sqlite';
import postStart from '../server/postStart';
import router from '@/router'; import router from '@/router';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
@ -60,6 +62,18 @@ export function loadExistingDatabase() {
}); });
} }
export async function connectToLocalDatabase(filepath) {
frappe.login('Administrator');
frappe.db = new SQLite({
dbPath: filepath
});
await frappe.db.connect();
await frappe.db.migrate();
await postStart();
// cache dbpath in localstorage
localStorage.dbPath = filepath;
}
export function showMessageDialog({ message, description, buttons = [] }) { export function showMessageDialog({ message, description, buttons = [] }) {
let buttonLabels = buttons.map(a => a.label); let buttonLabels = buttons.map(a => a.label);
remote.dialog.showMessageBox( remote.dialog.showMessageBox(

View File

@ -1,3 +1,4 @@
const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
module.exports = { module.exports = {
@ -16,7 +17,8 @@ module.exports = {
configureWebpack(config) { configureWebpack(config) {
Object.assign(config.resolve.alias, { Object.assign(config.resolve.alias, {
deepmerge$: 'deepmerge/dist/umd.js', deepmerge$: 'deepmerge/dist/umd.js',
'frappe-charts$': 'frappe-charts/dist/frappe-charts.esm.js' 'frappe-charts$': 'frappe-charts/dist/frappe-charts.esm.js',
'~': path.resolve('.')
}); });
config.plugins.push( config.plugins.push(