mirror of
https://github.com/frappe/books.git
synced 2024-11-10 07:40:55 +00:00
commit
6076b4f966
2
index.js
2
index.js
@ -208,7 +208,7 @@ module.exports = {
|
||||
return newDoc;
|
||||
},
|
||||
|
||||
async getNewDoc(doctype) {
|
||||
getNewDoc(doctype) {
|
||||
let doc = this.newDoc({ doctype: doctype });
|
||||
doc._notInserted = true;
|
||||
doc.name = frappe.getRandomString();
|
||||
|
@ -153,13 +153,27 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
this._validFieldsWithChildren.push(field);
|
||||
};
|
||||
|
||||
const doctype_fields = this.fields.map(field => field.fieldname);
|
||||
// fields validation
|
||||
this.fields.forEach((df, i) => {
|
||||
if (!df.fieldname) {
|
||||
throw new frappe.errors.ValidationError(
|
||||
`DocType ${this.name}: "fieldname" is required for field at index ${i}`
|
||||
);
|
||||
}
|
||||
if (!df.fieldtype) {
|
||||
throw new frappe.errors.ValidationError(
|
||||
`DocType ${this.name}: "fieldtype" is required for field "${df.fieldname}"`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const doctypeFields = this.fields.map(field => field.fieldname);
|
||||
|
||||
// standard fields
|
||||
for (let field of model.commonFields) {
|
||||
if (
|
||||
frappe.db.typeMap[field.fieldtype] &&
|
||||
!doctype_fields.includes(field.fieldname)
|
||||
!doctypeFields.includes(field.fieldname)
|
||||
) {
|
||||
_add(field);
|
||||
}
|
||||
@ -178,7 +192,7 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
for (let field of model.childFields) {
|
||||
if (
|
||||
frappe.db.typeMap[field.fieldtype] &&
|
||||
!doctype_fields.includes(field.fieldname)
|
||||
!doctypeFields.includes(field.fieldname)
|
||||
) {
|
||||
_add(field);
|
||||
}
|
||||
@ -188,7 +202,7 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
for (let field of model.parentFields) {
|
||||
if (
|
||||
frappe.db.typeMap[field.fieldtype] &&
|
||||
!doctype_fields.includes(field.fieldname)
|
||||
!doctypeFields.includes(field.fieldname)
|
||||
) {
|
||||
_add(field);
|
||||
}
|
||||
@ -200,7 +214,7 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
for (let field of model.treeFields) {
|
||||
if (
|
||||
frappe.db.typeMap[field.fieldtype] &&
|
||||
!doctype_fields.includes(field.fieldname)
|
||||
!doctypeFields.includes(field.fieldname)
|
||||
) {
|
||||
_add(field);
|
||||
}
|
||||
@ -270,7 +284,8 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
}
|
||||
if (!validValues.includes(value)) {
|
||||
throw new frappe.errors.ValueError(
|
||||
`Invalid value "${value}" for "${field.label}". Must be one of ${options.join(', ')}`
|
||||
// prettier-ignore
|
||||
`DocType ${this.name}: Invalid value "${value}" for "${field.label}". Must be one of ${options.join(', ')}`
|
||||
);
|
||||
}
|
||||
return value;
|
||||
|
40
model/migrate.js
Normal file
40
model/migrate.js
Normal file
@ -0,0 +1,40 @@
|
||||
const frappe = require('frappejs');
|
||||
|
||||
module.exports = async function migrate(allPatches, patchOrder) {
|
||||
let executedPatchRuns = [];
|
||||
try {
|
||||
executedPatchRuns = (
|
||||
await frappe.db.getAll({ doctype: 'PatchRun', fields: ['name'] })
|
||||
).map(d => d.name);
|
||||
} catch (error) {}
|
||||
|
||||
let patchRunOrder = patchOrder
|
||||
.map(text => {
|
||||
let [patch] = text.split(' ');
|
||||
if (text && patch) {
|
||||
return {
|
||||
fileName: text,
|
||||
method: allPatches[patch]
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
for (let patch of patchRunOrder) {
|
||||
if (!executedPatchRuns.includes(patch.fileName)) {
|
||||
await runPatch(patch);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function runPatch(patch) {
|
||||
try {
|
||||
await patch.method();
|
||||
let patchRun = frappe.getNewDoc('PatchRun');
|
||||
patchRun.name = patch.fileName;
|
||||
await patchRun.insert();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.log('Could not run patch', patch);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
module.exports = {
|
||||
name: "FilterGroup",
|
||||
isSingle: 0,
|
||||
isChild: 0,
|
||||
keywordFields: [],
|
||||
fields: [
|
||||
{
|
||||
fieldname: "name",
|
||||
label: "Name",
|
||||
fieldtype: "Data",
|
||||
required: 1
|
||||
},
|
||||
{
|
||||
fieldname: "forDocType",
|
||||
label: "Document Type",
|
||||
fieldtype: "Data",
|
||||
required: 1,
|
||||
disabled: 1,
|
||||
},
|
||||
{
|
||||
fieldname: "items",
|
||||
fieldtype: "Table",
|
||||
childtype: "FilterItem",
|
||||
label: "Items",
|
||||
required: 1
|
||||
}
|
||||
]
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
module.exports = {
|
||||
name: "FilterItem",
|
||||
doctype: "DocType",
|
||||
isSingle: 0,
|
||||
isChild: 1,
|
||||
keywordFields: [],
|
||||
fields: [
|
||||
{
|
||||
fieldname: "field",
|
||||
label: "Field",
|
||||
fieldtype: "Select",
|
||||
required: 1
|
||||
},
|
||||
{
|
||||
fieldname: "condition",
|
||||
label: "Condition",
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
'Equals',
|
||||
'>',
|
||||
'<',
|
||||
'>=',
|
||||
'<=',
|
||||
'Between',
|
||||
'Includes',
|
||||
'One Of'
|
||||
],
|
||||
required: 1
|
||||
},
|
||||
{
|
||||
fieldname: "value",
|
||||
label: "Value",
|
||||
fieldtype: "Data",
|
||||
}
|
||||
]
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
const frappe = require('frappejs');
|
||||
|
||||
module.exports = {
|
||||
name: "FilterSelector",
|
||||
label: "Set Filters",
|
||||
documentClass: require('./FilterSelectorDocument'),
|
||||
isSingle: 1,
|
||||
isChild: 0,
|
||||
keywordFields: [],
|
||||
fields: [
|
||||
{
|
||||
fieldname: "forDocType",
|
||||
label: "Document Type",
|
||||
fieldtype: "Data",
|
||||
hidden: 1,
|
||||
},
|
||||
{
|
||||
fieldname: "filterGroup",
|
||||
label: "Saved Filters",
|
||||
fieldtype: "Link",
|
||||
target: "FilterGroup",
|
||||
getFilters: (query, control) => {
|
||||
return {
|
||||
forDocType: control.doc.forDocType,
|
||||
keywords: ["like", query]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: "filterGroupName",
|
||||
label: "New Filter Name",
|
||||
fieldtype: "Data",
|
||||
},
|
||||
{
|
||||
fieldname: "items",
|
||||
label: "Items",
|
||||
fieldtype: "Table",
|
||||
childtype: "FilterItem",
|
||||
neverEmpty: 1,
|
||||
|
||||
// copy items from saved filter group
|
||||
formula: async (doc) => {
|
||||
if (doc._lastFilterGroup !== doc.filterGroup) {
|
||||
// fitler changed
|
||||
|
||||
if (doc.filterGroup) {
|
||||
doc.items = [];
|
||||
const filterGroup = await frappe.getDoc('FilterGroup', doc.filterGroup);
|
||||
|
||||
// copy items
|
||||
for(let source of filterGroup.items) {
|
||||
const item = Object.assign({}, source);
|
||||
item.parent = item.name = '';
|
||||
doc.items.push(item);
|
||||
}
|
||||
} else {
|
||||
// no filter group selected
|
||||
doc.items = [{idx: 0}];
|
||||
}
|
||||
|
||||
doc._lastFilterGroup = doc.filterGroup;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
],
|
||||
|
||||
formEvents: {
|
||||
// set the fields of the selected item in the 'select'
|
||||
refresh: (form) => {
|
||||
// override the `getOptions` method in the `field` property
|
||||
frappe.getMeta('FilterItem').getField('field').getOptions = () => {
|
||||
return frappe.getMeta(form.doc.forDocType).fields.map((f) => {
|
||||
return {label: f.label, value: f.fieldname};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
const BaseDocument = require('frappejs/model/document');
|
||||
const frappe = require('frappejs');
|
||||
|
||||
module.exports = class FormSelector extends BaseDocument {
|
||||
reset(doctype) {
|
||||
if (doctype) {
|
||||
this.forDocType = doctype;
|
||||
}
|
||||
this.items = [];
|
||||
this.filterGroup = '';
|
||||
this.filterGroupName = '';
|
||||
}
|
||||
|
||||
getFilters() {
|
||||
const filters = {};
|
||||
for (let item of (this.items || [])) {
|
||||
filters[item.field] = [(item.condition === 'Equals') ? '=' : item.condition,
|
||||
item.value];
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
setFilters(filters) {
|
||||
this.reset();
|
||||
for (let key in filters) {
|
||||
let value = filters[key];
|
||||
if (value instanceof Array) {
|
||||
this.items.push({field: key, condition: value[0], value: value[1]});
|
||||
} else {
|
||||
this.items.push({field: key, condition: 'Equals', value: value});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getText() {
|
||||
if (this.items && this.items.length) {
|
||||
this.forMeta = frappe.getMeta(this.forDocType);
|
||||
return this.items.map(v => `${this.forMeta.getLabel(v.field)} ${v.condition} ${v.value}`).join(', ');
|
||||
} else {
|
||||
return 'Set Filters';
|
||||
}
|
||||
}
|
||||
|
||||
async update() {
|
||||
// save new group filter
|
||||
if (frappe.isServer) {
|
||||
if (this.filterGroupName) {
|
||||
await this.makeFilterGroup();
|
||||
} else if (this.filterGroup) {
|
||||
await this.updateFilterGroup();
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
return super.update();
|
||||
}
|
||||
}
|
||||
|
||||
async makeFilterGroup() {
|
||||
const filterGroup = frappe.newDoc({doctype:'FilterGroup'});
|
||||
filterGroup.name = this.filterGroupName;
|
||||
this.updateFilterGroupValues(filterGroup);
|
||||
await filterGroup.insert();
|
||||
}
|
||||
|
||||
async updateFilterGroup() {
|
||||
const filterGroup = await frappe.getDoc('FilterGroup', this.filterGroup);
|
||||
this.updateFilterGroupValues(filterGroup);
|
||||
await filterGroup.update();
|
||||
}
|
||||
|
||||
updateFilterGroupValues(filterGroup) {
|
||||
filterGroup.forDocType = this.forDocType;
|
||||
filterGroup.items = [];
|
||||
for (let item of this.items) {
|
||||
filterGroup.items.push({field: item.field, condition: item.condition, value: item.value});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
const BaseForm = require('frappejs/client/view/form');
|
||||
const frappe = require('frappejs');
|
||||
|
||||
module.exports = class FilterSelectorForm extends BaseForm {
|
||||
makeSaveButton() {
|
||||
this.saveButton = this.container.addButton(frappe._("Apply"), 'primary', async (event) => {
|
||||
if (this.doc.filterGroupName || (this.doc.filterGroup && this.doc._dirty)) {
|
||||
// new filter, call update
|
||||
await this.save();
|
||||
}
|
||||
this.trigger('apply-filters');
|
||||
});
|
||||
}
|
||||
}
|
10
models/doctype/PatchRun/PatchRun.js
Normal file
10
models/doctype/PatchRun/PatchRun.js
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
name: 'PatchRun',
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'name',
|
||||
fieldtype: 'Data',
|
||||
label: 'Name'
|
||||
}
|
||||
]
|
||||
};
|
@ -1,7 +1,4 @@
|
||||
module.exports = {
|
||||
FilterItem: require('./doctype/FilterItem/FilterItem.js'),
|
||||
FilterGroup: require('./doctype/FilterGroup/FilterGroup.js'),
|
||||
FilterSelector: require('./doctype/FilterSelector/FilterSelector.js'),
|
||||
NumberSeries: require('./doctype/NumberSeries/NumberSeries.js'),
|
||||
PrintFormat: require('./doctype/PrintFormat/PrintFormat.js'),
|
||||
Role: require('./doctype/Role/Role.js'),
|
||||
@ -11,5 +8,6 @@ module.exports = {
|
||||
ToDo: require('./doctype/ToDo/ToDo.js'),
|
||||
User: require('./doctype/User/User.js'),
|
||||
UserRole: require('./doctype/UserRole/UserRole.js'),
|
||||
File: require('./doctype/File/File.js')
|
||||
File: require('./doctype/File/File.js'),
|
||||
PatchRun: require('./doctype/PatchRun/PatchRun.js')
|
||||
};
|
||||
|
@ -41,10 +41,8 @@ describe('Database Migrate', () => {
|
||||
let dbPath = '_migrate_test.db';
|
||||
server.init();
|
||||
let models = {
|
||||
models: {
|
||||
Person,
|
||||
Gender
|
||||
}
|
||||
Person,
|
||||
Gender
|
||||
};
|
||||
frappe.models = {};
|
||||
frappe.registerModels(models);
|
||||
@ -62,12 +60,15 @@ describe('Database Migrate', () => {
|
||||
// check if tables were created
|
||||
assert.deepEqual(['Gender', 'Person'], tables);
|
||||
|
||||
let fields = await frappe.db.sql('PRAGMA table_info(??)', 'Person')
|
||||
let fields = await frappe.db.sql('PRAGMA table_info(??)', 'Person');
|
||||
// check if standard fields and model fields were created
|
||||
assert.equal(fields.length, 8);
|
||||
assert.equal(fields.find(d => d.name === 'age').type, 'integer');
|
||||
|
||||
let foreignKeys = await frappe.db.sql('PRAGMA foreign_key_list(??)', 'Person')
|
||||
let foreignKeys = await frappe.db.sql(
|
||||
'PRAGMA foreign_key_list(??)',
|
||||
'Person'
|
||||
);
|
||||
// check for foreign keys
|
||||
assert.equal(foreignKeys.length, 1);
|
||||
assert.equal(foreignKeys[0].from, 'gender');
|
||||
|
@ -25,7 +25,15 @@ module.exports = {
|
||||
dateFormat = frappe.SystemSettings.dateFormat;
|
||||
}
|
||||
|
||||
value = luxon.DateTime.fromISO(value).toFormat(dateFormat);
|
||||
if (typeof value === 'string') {
|
||||
// ISO String
|
||||
value = luxon.DateTime.fromISO(value);
|
||||
} else if (Object.prototype.toString.call(value) === '[object Date]') {
|
||||
// JS Date
|
||||
value = luxon.DateTime.fromJSDate(value);
|
||||
}
|
||||
|
||||
value = value.toFormat(dateFormat);
|
||||
if (value === 'Invalid DateTime') {
|
||||
value = '';
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const deepmerge = require('deepmerge');
|
||||
const defaultsDeep = require('lodash/defaultsDeep');
|
||||
const logger = require('./logger');
|
||||
|
||||
const frappeConf = 'frappe.conf.js';
|
||||
@ -30,7 +30,7 @@ function getAppConfig() {
|
||||
}
|
||||
}
|
||||
const appConfig = require(path.resolve(getAppDir(), frappeConf));
|
||||
return deepmerge(defaults, appConfig);
|
||||
return defaultsDeep(defaults, appConfig);
|
||||
}
|
||||
|
||||
function resolveAppDir(...args) {
|
||||
@ -41,4 +41,4 @@ module.exports = {
|
||||
getAppDir,
|
||||
getAppConfig,
|
||||
resolveAppDir
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user