diff --git a/models/doctype/Contact/Contact.js b/models/doctype/Contact/Contact.js
index c9853f38..d15bc658 100644
--- a/models/doctype/Contact/Contact.js
+++ b/models/doctype/Contact/Contact.js
@@ -64,7 +64,6 @@ export default {
return ['fullName'];
},
getRowHTML(list, data) {
- console.log(list, data);
return `
${list.getNameHTML(data)}
`;
}
},
diff --git a/models/doctype/Tax/RegionalChanges.js b/models/doctype/Tax/RegionalChanges.js
index 48476533..b9104274 100644
--- a/models/doctype/Tax/RegionalChanges.js
+++ b/models/doctype/Tax/RegionalChanges.js
@@ -1,41 +1,49 @@
+import frappe from 'frappejs';
+
export default async function generateTaxes(country) {
if (country === 'India') {
const GSTs = {
GST: [28, 18, 12, 6, 5, 3, 0.25, 0],
IGST: [28, 18, 12, 6, 5, 3, 0.25, 0],
'Exempt-GST': [0],
- 'Exempt-IGST': [0]
+ 'Exempt-IGST': [0],
};
let newTax = await frappe.getNewDoc('Tax');
+
for (const type of Object.keys(GSTs)) {
for (const percent of GSTs[type]) {
- if (type === 'GST') {
- await newTax.set({
- name: `${type}-${percent}`,
- details: [
- {
- account: 'CGST',
- rate: percent / 2
- },
- {
- account: 'SGST',
- rate: percent / 2
- }
- ]
- });
- } else {
- await newTax.set({
- name: `${type}-${percent}`,
- details: [
- {
- account: type.toString().split('-')[0],
- rate: percent
- }
- ]
- });
- }
+ const name = `${type}-${percent}`;
+
+ // Not cross checking cause hardcoded values.
+ await frappe.db.knex('Tax').where({ name }).del();
+ await frappe.db.knex('TaxDetail').where({ parent: name }).del();
+
+ const details = getTaxDetails(type, percent);
+ await newTax.set({ name, details });
await newTax.insert();
}
}
}
-};
+}
+
+function getTaxDetails(type, percent) {
+ if (type === 'GST') {
+ return [
+ {
+ account: 'CGST',
+ rate: percent / 2,
+ },
+ {
+ account: 'SGST',
+ rate: percent / 2,
+ },
+ ];
+ } else {
+ return [
+ {
+ account: type.toString().split('-')[0],
+ rate: percent,
+ },
+ ];
+ }
+}
diff --git a/reports/AccountsReceivablePayable/AccountsReceivablePayable.js b/reports/AccountsReceivablePayable/AccountsReceivablePayable.js
index ada10d0c..3626909b 100644
--- a/reports/AccountsReceivablePayable/AccountsReceivablePayable.js
+++ b/reports/AccountsReceivablePayable/AccountsReceivablePayable.js
@@ -31,8 +31,6 @@ async function getReceivablePayable({ reportType = 'Receivable', date }) {
for (let entry of validEntries) {
const { outStandingAmount, creditNoteAmount } = getOutstandingAmount(entry);
- console.log(outStandingAmount);
-
if (outStandingAmount > 0.1 / 10) {
const row = {
date: entry.date,
diff --git a/src/migrate.js b/src/migrate.js
index 609ef74f..19c24a11 100644
--- a/src/migrate.js
+++ b/src/migrate.js
@@ -1,11 +1,28 @@
import frappe from 'frappejs';
-import migrate from 'frappejs/model/migrate';
+import runPatches from 'frappejs/model/runPatches';
import patchesTxt from '../patches/patches.txt';
const requirePatch = require.context('../patches', true, /\w+\.(js)$/);
export default async function runMigrate() {
- let patchOrder = patchesTxt.split('\n');
- let allPatches = {};
+ if (await canRunPatches()) {
+ const patchOrder = patchesTxt.split('\n');
+ const allPatches = getAllPatches();
+ await runPatches(allPatches, patchOrder);
+ }
+ await frappe.db.migrate();
+}
+
+async function canRunPatches() {
+ return (
+ (await frappe.db
+ .knex('sqlite_master')
+ .where({ type: 'table', name: 'PatchRun' })
+ .select('name').length) > 0
+ );
+}
+
+async function getAllPatches() {
+ const allPatches = {};
requirePatch.keys().forEach((fileName) => {
if (fileName === './index.js') return;
let method;
@@ -20,6 +37,5 @@ export default async function runMigrate() {
allPatches[fileName] = method;
}
});
- await migrate(allPatches, patchOrder);
- await frappe.db.migrate();
-};
+ return allPatches;
+}
diff --git a/src/pages/DatabaseSelector.vue b/src/pages/DatabaseSelector.vue
index ac4b41e5..be70ad9b 100644
--- a/src/pages/DatabaseSelector.vue
+++ b/src/pages/DatabaseSelector.vue
@@ -139,7 +139,7 @@ export default {
};
},
mounted() {
- this.files = config.get('files', []).filter(({filepath}) => fs.existsSync(filepath));
+ this.files = config.get('files', []).filter(({filePath}) => fs.existsSync(filePath));
this.showFiles = this.files.length > 0;
},
methods: {
@@ -158,6 +158,10 @@ export default {
await this.connectToDatabase(file.filePath);
},
async connectToDatabase(filePath) {
+ if (!filePath) {
+ return;
+ }
+
this.loadingDatabase = true;
const connectionSuccess = await connectToLocalDatabase(filePath);
this.loadingDatabase = false;
diff --git a/src/pages/SetupWizard/SetupWizard.vue b/src/pages/SetupWizard/SetupWizard.vue
index 81960658..8936dbab 100644
--- a/src/pages/SetupWizard/SetupWizard.vue
+++ b/src/pages/SetupWizard/SetupWizard.vue
@@ -65,6 +65,10 @@ import FormControl from '@/components/Controls/FormControl';
import Button from '@/components/Button';
import setupCompany from './setupCompany';
import Popover from '@/components/Popover';
+import config from '@/config';
+import path from 'path';
+import fs from 'fs';
+import { connectToLocalDatabase } from '@/utils';
import {
getErrorMessage,
@@ -121,24 +125,31 @@ export default {
showMessageDialog({ message: this._('Please fill all values') });
return;
}
+
try {
this.loading = true;
await setupCompany(this.doc);
this.$emit('setup-complete');
} catch (e) {
this.loading = false;
- console.log(e, this.doc);
if (e.type === frappe.errors.DuplicateEntryError) {
- // TODO: Add option to overwrite file from here.
- const message = this._(
- 'Records already exist in the db. Please create a new database file and try again.'
- );
- showMessageDialog({ message });
+ await this.renameDbFileAndRerunSetup();
} else {
handleErrorWithDialog(e, this.doc);
}
}
},
+ async renameDbFileAndRerunSetup() {
+ const filePath = config.get('lastSelectedFilePath');
+ renameDbFile(filePath);
+ frappe.removeFromCache('AccountingSettings', 'AccountingSettings');
+ delete frappe.AccountingSettings;
+ const connectionSuccess = await connectToLocalDatabase(filePath);
+ if (connectionSuccess) {
+ await setupCompany(this.doc);
+ this.$emit('setup-complete');
+ }
+ },
},
computed: {
meta() {
@@ -152,4 +163,14 @@ export default {
},
},
};
+
+function renameDbFile(filePath) {
+ const dirname = path.dirname(filePath);
+ const basename = path.basename(filePath);
+ const backupPath = path.join(dirname, `_${basename}`);
+ if (fs.existsSync(backupPath)) {
+ fs.unlinkSync(backupPath);
+ }
+ fs.renameSync(filePath, backupPath);
+}
diff --git a/src/pages/SetupWizard/setupCompany.js b/src/pages/SetupWizard/setupCompany.js
index 7742733e..82dae91a 100644
--- a/src/pages/SetupWizard/setupCompany.js
+++ b/src/pages/SetupWizard/setupCompany.js
@@ -12,7 +12,7 @@ export default async function setupCompany(setupWizardValues) {
email,
bankName,
fiscalYearStart,
- fiscalYearEnd
+ fiscalYearEnd,
} = setupWizardValues;
const accountingSettings = frappe.AccountingSettings;
@@ -24,7 +24,7 @@ export default async function setupCompany(setupWizardValues) {
bankName,
fiscalYearStart,
fiscalYearEnd,
- currency: countryList[country]['currency']
+ currency: countryList[country]['currency'],
});
const printSettings = await frappe.getSingle('PrintSettings');
@@ -32,7 +32,7 @@ export default async function setupCompany(setupWizardValues) {
logo: companyLogo,
companyName,
email,
- displayLogo: companyLogo ? 1 : 0
+ displayLogo: companyLogo ? 1 : 0,
});
await setupGlobalCurrencies(countryList);
@@ -55,24 +55,28 @@ async function setupGlobalCurrencies(countries) {
currency_fraction_units: fractionUnits,
smallest_currency_fraction_value: smallestValue,
currency_symbol: symbol,
- number_format: numberFormat
+ 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);
- }
+ if (!currency || queue.includes(currency)) {
+ continue;
+ }
+
+ const docObject = {
+ doctype: 'Currency',
+ name: currency,
+ fraction,
+ fractionUnits,
+ smallestValue,
+ symbol,
+ numberFormat: numberFormat || '#,###.##',
+ };
+
+ const canCreate = await checkIfExactRecordAbsent(docObject);
+ if (canCreate) {
+ const doc = await frappe.newDoc(docObject);
+ promises.push(doc.insert());
+ queue.push(currency);
}
}
return Promise.all(promises);
@@ -80,26 +84,30 @@ async function setupGlobalCurrencies(countries) {
async function setupChartOfAccounts(bankName) {
await frappe.call({
- method: 'import-coa'
+ method: 'import-coa',
});
- const accountDoc = await frappe.newDoc({
- doctype: 'Account'
- });
- Object.assign(accountDoc, {
+ const docObject = {
+ doctype: 'Account',
name: bankName,
rootType: 'Asset',
parentAccount: 'Bank Accounts',
accountType: 'Bank',
- isGroup: 0
- });
- accountDoc.insert();
+ isGroup: 0,
+ };
+
+ if (await checkIfExactRecordAbsent(docObject)) {
+ const accountDoc = await frappe.newDoc(docObject);
+ accountDoc.insert();
+ }
}
async function setupRegionalChanges(country) {
await generateTaxes(country);
if (country === 'India') {
- frappe.models.Party = await import('../../../models/doctype/Party/RegionalChanges');
+ frappe.models.Party = await import(
+ '../../../models/doctype/Party/RegionalChanges'
+ );
await frappe.db.migrate();
}
}
@@ -107,10 +115,35 @@ async function setupRegionalChanges(country) {
function updateCompanyNameInConfig() {
let filePath = frappe.db.dbPath;
let files = config.get('files', []);
- files.forEach(file => {
+ files.forEach((file) => {
if (file.filePath === filePath) {
file.companyName = frappe.AccountingSettings.companyName;
}
});
config.set('files', files);
}
+
+export async function checkIfExactRecordAbsent(docObject) {
+ const { doctype, name } = docObject;
+ const newDocObject = Object.assign({}, docObject);
+ delete newDocObject.doctype;
+ const rows = await frappe.db.knex(doctype).where({ name });
+
+ if (rows.length === 0) {
+ return true;
+ }
+
+ const storedDocObject = rows[0];
+ const matchList = Object.keys(newDocObject).map((key) => {
+ const newValue = newDocObject[key];
+ const storedValue = storedDocObject[key];
+ return newValue == storedValue; // Should not be type sensitive.
+ });
+
+ if (!matchList.every(Boolean)) {
+ await frappe.db.knex(doctype).where({ name }).del();
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/utils.js b/src/utils.js
index 156a335c..9fcae637 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -16,38 +16,24 @@ export async function createNewDatabase() {
defaultPath: 'frappe-books.db',
};
- let { filePath } = await ipcRenderer.invoke(
+ let { canceled, filePath } = await ipcRenderer.invoke(
IPC_ACTIONS.GET_SAVE_FILEPATH,
options
);
- if (filePath) {
- if (!filePath.endsWith('.db')) {
- filePath = filePath + '.db';
- }
- if (fs.existsSync(filePath)) {
- showMessageDialog({
- // prettier-ignore
- message: _('A file exists with the same name and it will be overwritten. Are you sure you want to continue?'),
- buttons: [
- {
- label: _('Overwrite'),
- action() {
- fs.unlinkSync(filePath);
- return filePath;
- },
- },
- {
- label: _('Cancel'),
- action() {
- return '';
- },
- },
- ],
- });
- } else {
- return filePath;
- }
+
+ if (canceled || filePath.length === 0) {
+ return '';
}
+
+ if (!filePath.endsWith('.db')) {
+ filePath = filePath + '.db';
+ }
+
+ if (fs.existsSync(filePath)) {
+ fs.unlinkSync(filePath);
+ }
+
+ return filePath;
}
export async function loadExistingDatabase() {
@@ -67,30 +53,31 @@ export async function loadExistingDatabase() {
}
}
-export async function connectToLocalDatabase(filepath) {
- if (!filepath) {
+export async function connectToLocalDatabase(filePath) {
+ if (!filePath) {
return false;
}
frappe.login('Administrator');
try {
frappe.db = new SQLite({
- dbPath: filepath,
+ dbPath: filePath,
});
await frappe.db.connect();
} catch (error) {
return false;
}
+
await migrate();
await postStart();
// set file info in config
let files = config.get('files') || [];
- if (!files.find((file) => file.filePath === filepath)) {
+ if (!files.find((file) => file.filePath === filePath)) {
files = [
{
companyName: frappe.AccountingSettings.companyName,
- filePath: filepath,
+ filePath: filePath,
},
...files,
];
@@ -98,7 +85,7 @@ export async function connectToLocalDatabase(filepath) {
}
// set last selected file
- config.set('lastSelectedFilePath', filepath);
+ config.set('lastSelectedFilePath', filePath);
return true;
}
@@ -274,4 +261,4 @@ export async function runWindowAction(name) {
break;
}
return name;
-}
+}
\ No newline at end of file