2
0
mirror of https://github.com/frappe/books.git synced 2025-01-10 18:24:40 +00:00

Merge pull request #359 from 18alantom/custom-number-series

feat: custom number series
This commit is contained in:
Alan 2022-03-08 15:23:32 +05:30 committed by GitHub
commit b4397a9132
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 336 additions and 143 deletions

View File

@ -30,8 +30,18 @@ class SqliteDatabase extends Database {
// create temp table // create temp table
await this.createTable(doctype, tempName); await this.createTable(doctype, tempName);
// copy from old to new table try {
await this.knex(tempName).insert(this.knex.select().from(doctype)); // copy from old to new table
await this.knex(tempName).insert(this.knex.select().from(doctype));
} catch (err) {
await this.sql('ROLLBACK');
await this.sql('PRAGMA foreign_keys=ON');
const rows = await this.knex.select().from(doctype);
await this.prestigeTheTable(doctype, rows);
return;
}
// drop old table // drop old table
await this.knex.schema.dropTable(doctype); await this.knex.schema.dropTable(doctype);
@ -110,6 +120,7 @@ class SqliteDatabase extends Database {
// Alter table hacx for sqlite in case of schema change. // Alter table hacx for sqlite in case of schema change.
const tempName = `__${tableName}`; const tempName = `__${tableName}`;
await this.knex.schema.dropTableIfExists(tempName); await this.knex.schema.dropTableIfExists(tempName);
await this.knex.raw('PRAGMA foreign_keys=OFF'); await this.knex.raw('PRAGMA foreign_keys=OFF');
await this.createTable(tableName, tempName); await this.createTable(tableName, tempName);

View File

@ -1,3 +1,4 @@
const { getPaddedName } = require('@/utils');
const frappe = require('frappe'); const frappe = require('frappe');
const { getRandomString } = require('frappe/utils'); const { getRandomString } = require('frappe/utils');
@ -28,11 +29,23 @@ module.exports = {
return; return;
} }
// Current, per doc number series
if (doc.numberSeries) {
doc.name = await this.getSeriesNext(doc.numberSeries, doc.doctype);
return;
}
// if(doc.meta)
// Legacy, using doc settings for number series
if (doc.meta.settings) { if (doc.meta.settings) {
const numberSeries = (await doc.getSettings()).numberSeries; const numberSeries = (await doc.getSettings()).numberSeries;
if (numberSeries) { if (!numberSeries) {
doc.name = await this.getSeriesNext(numberSeries, doc.doctype); return;
} }
doc.name = await this.getSeriesNext(numberSeries, doc.doctype);
return;
} }
} }
@ -78,33 +91,34 @@ module.exports = {
async getSeriesNext(prefix, doctype) { async getSeriesNext(prefix, doctype) {
let series; let series;
try { try {
series = await frappe.getDoc('NumberSeries', prefix); series = await frappe.getDoc('NumberSeries', prefix);
} catch (e) { } catch (e) {
if (!e.statusCode || e.statusCode !== 404) { if (!e.statusCode || e.statusCode !== 404) {
throw e; throw e;
} }
await this.createNumberSeries(prefix);
await this.createNumberSeries(prefix, doctype);
series = await frappe.getDoc('NumberSeries', prefix); series = await frappe.getDoc('NumberSeries', prefix);
} }
let next = await series.next(doctype);
return prefix + next; return await series.next(doctype);
}, },
async createNumberSeries(prefix, setting, start = 1001) { async createNumberSeries(prefix, referenceType, start = 1001) {
if (!(await frappe.db.exists('NumberSeries', prefix))) { const exists = await frappe.db.exists('NumberSeries', prefix);
const series = frappe.newDoc({ if (exists) {
doctype: 'NumberSeries', return;
name: prefix,
current: start,
});
await series.insert();
if (setting) {
const settingDoc = await frappe.getSingle(setting);
settingDoc.numberSeries = series.name;
await settingDoc.update();
}
} }
const series = frappe.newDoc({
doctype: 'NumberSeries',
name: prefix,
start,
referenceType,
});
await series.insert();
}, },
}; };

View File

@ -1,5 +1,18 @@
const { t } = require('frappe'); const { t } = require('frappe');
const referenceTypeMap = {
SalesInvoice: t`Invoice`,
PurchaseInvoice: t`Bill`,
Payment: t`Payment`,
JournalEntry: t`Journal Entry`,
Quotation: t`Quotation`,
SalesOrder: t`SalesOrder`,
Fulfillment: t`Fulfillment`,
PurchaseOrder: t`PurchaseOrder`,
PurchaseReceipt: t`PurchaseReceipt`,
'-': t`None`,
};
module.exports = { module.exports = {
name: 'NumberSeries', name: 'NumberSeries',
documentClass: require('./NumberSeriesDocument.js'), documentClass: require('./NumberSeriesDocument.js'),
@ -14,11 +27,38 @@ module.exports = {
fieldtype: 'Data', fieldtype: 'Data',
required: 1, required: 1,
}, },
{
fieldname: 'start',
label: t`Start`,
fieldtype: 'Int',
default: 1001,
required: 1,
minvalue: 0,
},
{
fieldname: 'padZeros',
label: t`Pad Zeros`,
fieldtype: 'Int',
default: 4,
required: 1,
},
{
fieldname: 'referenceType',
label: t`Reference Type`,
fieldtype: 'Select',
options: Object.keys(referenceTypeMap),
map: referenceTypeMap,
default: '-',
required: 1,
readOnly: 1,
},
{ {
fieldname: 'current', fieldname: 'current',
label: t`Current`, label: t`Current`,
fieldtype: 'Int', fieldtype: 'Int',
required: 1, required: 1,
readOnly: 1,
}, },
], ],
quickEditFields: ['start', 'padZeros', 'referenceType'],
}; };

View File

@ -1,12 +1,14 @@
const { getPaddedName } = require('@/utils');
const frappe = require('frappe'); const frappe = require('frappe');
const BaseDocument = require('frappe/model/document'); const BaseDocument = require('frappe/model/document');
module.exports = class NumberSeries extends BaseDocument { module.exports = class NumberSeries extends BaseDocument {
validate() { validate() {
if (this.current === null || this.current === undefined) { if (!this.current) {
this.current = 0; this.current = this.start;
} }
} }
async next(doctype) { async next(doctype) {
this.validate(); this.validate();
@ -17,13 +19,19 @@ module.exports = class NumberSeries extends BaseDocument {
this.current++; this.current++;
await this.update(); await this.update();
return this.current; return this.getPaddedName(this.current);
} }
async checkIfCurrentExists(doctype) { async checkIfCurrentExists(doctype) {
if (!doctype) { if (!doctype) {
return true; return true;
} }
return await frappe.db.exists(doctype, this.name + this.current);
const name = this.getPaddedName(this.current);
return await frappe.db.exists(doctype, name);
}
getPaddedName(next) {
return getPaddedName(this.name, next, this.padZeros);
} }
}; };

View File

@ -1,4 +1,15 @@
export const DEFAULT_INTERNAL_PRECISION = 11; export const DEFAULT_INTERNAL_PRECISION = 11;
export const DEFAULT_DISPLAY_PRECISION = 2; export const DEFAULT_DISPLAY_PRECISION = 2;
export const DEFAULT_LOCALE = 'en-IN'; export const DEFAULT_LOCALE = 'en-IN';
export const DEFAULT_LANGUAGE = 'English'; export const DEFAULT_LANGUAGE = 'English';
export const DEFAULT_NUMBER_SERIES = {
SalesInvoice: 'SINV-',
PurchaseInvoice: 'PINV-',
Payment: 'PAY-',
JournalEntry: 'JV-',
Quotation: 'QTN-',
SalesOrder: 'SO-',
Fulfillment: 'OF-',
PurchaseOrder: 'PO-',
PurchaseReceipt: 'PREC-',
};

View File

@ -1,5 +1,6 @@
import { t } from 'frappe'; import { t } from 'frappe';
import model from 'frappe/model'; import model from 'frappe/model';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import Quotation from '../Quotation/Quotation'; import Quotation from '../Quotation/Quotation';
export default model.extend(Quotation, { export default model.extend(Quotation, {
@ -11,5 +12,16 @@ export default model.extend(Quotation, {
fieldname: 'items', fieldname: 'items',
childtype: 'FulfillmentItem', childtype: 'FulfillmentItem',
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'Fulfillment' };
},
default: DEFAULT_NUMBER_SERIES['FulFillment'],
},
], ],
}); });

View File

@ -5,10 +5,5 @@ import QuotationSettings from '../QuotationSettings/QuotationSettings';
export default model.extend(QuotationSettings, { export default model.extend(QuotationSettings, {
name: 'FulfillmentSettings', name: 'FulfillmentSettings',
label: t`Fulfillment Settings`, label: t`Fulfillment Settings`,
fields: [ fields: [],
{
fieldname: 'numberSeries',
default: 'OF',
},
],
}); });

View File

@ -1,6 +1,7 @@
import { t } from 'frappe'; import { t } from 'frappe';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { ledgerLink } from '../../../accounting/utils'; import { ledgerLink } from '../../../accounting/utils';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
export default { export default {
label: t`Journal Entry`, label: t`Journal Entry`,
@ -72,6 +73,17 @@ export default {
default: 0, default: 0,
readOnly: 1, readOnly: 1,
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'JournalEntry' };
},
default: DEFAULT_NUMBER_SERIES['JournalEntry'],
},
], ],
actions: [ledgerLink], actions: [ledgerLink],
}; };

View File

@ -6,14 +6,5 @@ export default {
isSingle: 1, isSingle: 1,
isChild: 0, isChild: 0,
keywordFields: [], keywordFields: [],
fields: [ fields: [],
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
default: 'JV',
},
],
}; };

View File

@ -1,5 +1,6 @@
import frappe, { t } from 'frappe'; import frappe, { t } from 'frappe';
import utils from '../../../accounting/utils'; import utils from '../../../accounting/utils';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
export default { export default {
name: 'Payment', name: 'Payment',
@ -81,6 +82,17 @@ export default {
} }
}, },
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'Payment' };
},
default: DEFAULT_NUMBER_SERIES['Payment'],
},
{ {
fieldname: 'paymentMethod', fieldname: 'paymentMethod',
label: t`Payment Method`, label: t`Payment Method`,
@ -162,6 +174,7 @@ export default {
], ],
quickEditFields: [ quickEditFields: [
'numberSeries',
'party', 'party',
'date', 'date',
'paymentMethod', 'paymentMethod',

View File

@ -6,14 +6,5 @@ export default {
isSingle: 1, isSingle: 1,
isChild: 0, isChild: 0,
keywordFields: [], keywordFields: [],
fields: [ fields: [],
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
default: 'PAY',
},
],
}; };

View File

@ -1,4 +1,5 @@
import { t } from 'frappe'; import { t } from 'frappe';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import InvoiceTemplate from '../SalesInvoice/InvoiceTemplate.vue'; import InvoiceTemplate from '../SalesInvoice/InvoiceTemplate.vue';
import { getActions } from '../Transaction/Transaction'; import { getActions } from '../Transaction/Transaction';
import PurchaseInvoice from './PurchaseInvoiceDocument'; import PurchaseInvoice from './PurchaseInvoiceDocument';
@ -134,6 +135,17 @@ export default {
default: 0, default: 0,
readOnly: 1, readOnly: 1,
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'PurchaseInvoice' };
},
default: DEFAULT_NUMBER_SERIES['PurchaseInvoice'],
},
], ],
actions: getActions('PurchaseInvoice'), actions: getActions('PurchaseInvoice'),

View File

@ -6,14 +6,5 @@ export default {
isSingle: 1, isSingle: 1,
isChild: 0, isChild: 0,
keywordFields: [], keywordFields: [],
fields: [ fields: [],
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
default: 'PINV',
},
],
}; };

View File

@ -1,5 +1,6 @@
import { t } from 'frappe'; import { t } from 'frappe';
import model from 'frappe/model'; import model from 'frappe/model';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import PurchaseInvoice from '../PurchaseInvoice/PurchaseInvoice'; import PurchaseInvoice from '../PurchaseInvoice/PurchaseInvoice';
export default model.extend( export default model.extend(
@ -13,6 +14,17 @@ export default model.extend(
fieldname: 'items', fieldname: 'items',
childtype: 'PurchaseOrderItem', childtype: 'PurchaseOrderItem',
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'PurchaseOrder' };
},
default: DEFAULT_NUMBER_SERIES['PurchaseOrder'],
},
], ],
}, },
{ {

View File

@ -5,10 +5,5 @@ import PurchaseInvoiceSettings from '../PurchaseInvoiceSettings/PurchaseInvoiceS
export default model.extend(PurchaseInvoiceSettings, { export default model.extend(PurchaseInvoiceSettings, {
name: 'PurchaseOrderSettings', name: 'PurchaseOrderSettings',
label: t`Purchase Order Settings`, label: t`Purchase Order Settings`,
fields: [ fields: [],
{
fieldname: 'numberSeries',
default: 'PO',
},
],
}); });

View File

@ -1,5 +1,6 @@
import { t } from 'frappe'; import { t } from 'frappe';
import model from 'frappe/model'; import model from 'frappe/model';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import PurchaseOrder from '../PurchaseOrder/PurchaseOrder'; import PurchaseOrder from '../PurchaseOrder/PurchaseOrder';
export default model.extend(PurchaseOrder, { export default model.extend(PurchaseOrder, {
@ -11,5 +12,16 @@ export default model.extend(PurchaseOrder, {
fieldname: 'items', fieldname: 'items',
childtype: 'PurchaseReceiptItem', childtype: 'PurchaseReceiptItem',
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'PurchaseReceipt' };
},
default: DEFAULT_NUMBER_SERIES['PurchaseReceipt'],
},
], ],
}); });

View File

@ -5,10 +5,5 @@ import PurchaseOrderSettings from '../PurchaseOrderSettings/PurchaseOrderSetting
export default model.extend(PurchaseOrderSettings, { export default model.extend(PurchaseOrderSettings, {
name: 'PurchaseReceiptSettings', name: 'PurchaseReceiptSettings',
label: t`Purchase Receipt Settings`, label: t`Purchase Receipt Settings`,
fields: [ fields: [],
{
fieldname: 'numberSeries',
default: 'PREC',
},
],
}); });

View File

@ -1,5 +1,6 @@
import { t } from 'frappe'; import { t } from 'frappe';
import model from 'frappe/model'; import model from 'frappe/model';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import SalesInvoice from '../SalesInvoice/SalesInvoice'; import SalesInvoice from '../SalesInvoice/SalesInvoice';
const Quotation = model.extend( const Quotation = model.extend(
@ -13,6 +14,17 @@ const Quotation = model.extend(
fieldname: 'items', fieldname: 'items',
childtype: 'QuotationItem', childtype: 'QuotationItem',
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'Quotation' };
},
default: DEFAULT_NUMBER_SERIES['Quotation'],
},
], ],
links: [], links: [],
}, },

View File

@ -5,10 +5,5 @@ import SalesInvoiceSettings from '../SalesInvoiceSettings/SalesInvoiceSettings';
export default model.extend(SalesInvoiceSettings, { export default model.extend(SalesInvoiceSettings, {
name: 'QuotationSettings', name: 'QuotationSettings',
label: t`Quotation Settings`, label: t`Quotation Settings`,
fields: [ fields: [],
{
fieldname: 'numberSeries',
default: 'QTN',
},
],
}); });

View File

@ -1,4 +1,5 @@
import { t } from 'frappe'; import { t } from 'frappe';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import { getActions } from '../Transaction/Transaction'; import { getActions } from '../Transaction/Transaction';
import InvoiceTemplate from './InvoiceTemplate.vue'; import InvoiceTemplate from './InvoiceTemplate.vue';
import SalesInvoice from './SalesInvoiceDocument'; import SalesInvoice from './SalesInvoiceDocument';
@ -134,6 +135,17 @@ export default {
default: 0, default: 0,
readOnly: 1, readOnly: 1,
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'SalesInvoice' };
},
default: DEFAULT_NUMBER_SERIES['SalesInvoice'],
},
], ],
actions: getActions('SalesInvoice'), actions: getActions('SalesInvoice'),

View File

@ -7,14 +7,6 @@ export default {
isChild: 0, isChild: 0,
keywordFields: [], keywordFields: [],
fields: [ fields: [
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
default: 'SINV',
},
{ {
fieldname: 'template', fieldname: 'template',
label: t`Template`, label: t`Template`,

View File

@ -1,5 +1,6 @@
import { t } from 'frappe'; import { t } from 'frappe';
import model from 'frappe/model'; import model from 'frappe/model';
import { DEFAULT_NUMBER_SERIES } from '../../../frappe/utils/consts';
import Quotation from '../Quotation/Quotation'; import Quotation from '../Quotation/Quotation';
export default model.extend(Quotation, { export default model.extend(Quotation, {
@ -11,5 +12,16 @@ export default model.extend(Quotation, {
fieldname: 'items', fieldname: 'items',
childtype: 'SalesOrderItem', childtype: 'SalesOrderItem',
}, },
{
fieldname: 'numberSeries',
label: t`Number Series`,
fieldtype: 'Link',
target: 'NumberSeries',
required: 1,
getFilters: () => {
return { referenceType: 'SalesOrder' };
},
default: DEFAULT_NUMBER_SERIES['SalesOrder'],
},
], ],
}); });

View File

@ -5,10 +5,5 @@ import QuotationSettings from '../QuotationSettings/QuotationSettings';
export default model.extend(QuotationSettings, { export default model.extend(QuotationSettings, {
name: 'SalesOrderSettings', name: 'SalesOrderSettings',
label: t`Sales Order Settings`, label: t`Sales Order Settings`,
fields: [ fields: [],
{
fieldname: 'numberSeries',
default: 'SO',
},
],
}); });

View File

@ -0,0 +1,20 @@
import { invertMap } from '@/utils';
import frappe from 'frappe';
import { DEFAULT_NUMBER_SERIES } from 'frappe/utils/consts';
async function setReferencesOnNumberSeries() {
const map = invertMap(DEFAULT_NUMBER_SERIES);
const rows = await frappe.db.knex('NumberSeries');
for (const row of rows) {
if (row.referenceType === map[row.name]) {
return;
}
row.referenceType = map[row.name];
}
await frappe.db.prestigeTheTable('NumberSeries', rows);
}
export default async function execute() {
await setReferencesOnNumberSeries();
}

View File

@ -8,5 +8,10 @@
"version": "0.0.4", "version": "0.0.4",
"fileName": "convertCurrencyToStrings", "fileName": "convertCurrencyToStrings",
"beforeMigrate": true "beforeMigrate": true
},
{
"version": "0.3.2",
"fileName": "moveNumberSeriesFromSettings",
"beforeMigrate": false
} }
] ]

View File

@ -20,15 +20,15 @@ export default async function postStart() {
frappe.metaCache = {}; frappe.metaCache = {};
// init naming series if missing // init naming series if missing
await naming.createNumberSeries('SINV-', 'SalesInvoiceSettings'); await naming.createNumberSeries('SINV-', 'SalesInvoice');
await naming.createNumberSeries('PINV-', 'PurchaseInvoiceSettings'); await naming.createNumberSeries('PINV-', 'PurchaseInvoice');
await naming.createNumberSeries('PAY-', 'PaymentSettings'); await naming.createNumberSeries('PAY-', 'Payment');
await naming.createNumberSeries('JV-', 'JournalEntrySettings'); await naming.createNumberSeries('JV-', 'JournalEntry');
await naming.createNumberSeries('QTN-', 'QuotationSettings'); // await naming.createNumberSeries('QTN-', 'QuotationSettings');
await naming.createNumberSeries('SO-', 'SalesOrderSettings'); // await naming.createNumberSeries('SO-', 'SalesOrderSettings');
await naming.createNumberSeries('OF-', 'FulfillmentSettings'); // await naming.createNumberSeries('OF-', 'FulfillmentSettings');
await naming.createNumberSeries('PO-', 'PurchaseOrderSettings'); // await naming.createNumberSeries('PO-', 'PurchaseOrderSettings');
await naming.createNumberSeries('PREC-', 'PurchaseReceiptSettings'); // await naming.createNumberSeries('PREC-', 'PurchaseReceiptSettings');
// fetch singles // fetch singles
// so that they are available synchronously // so that they are available synchronously

View File

@ -1,10 +1,9 @@
<script> <script>
import frappe from 'frappe';
import AutoComplete from './AutoComplete';
import Badge from '@/components/Badge'; import Badge from '@/components/Badge';
import { openQuickEdit } from '@/utils'; import { openQuickEdit } from '@/utils';
import frappe, { t } from 'frappe';
import { markRaw } from 'vue'; import { markRaw } from 'vue';
import { t } from 'frappe'; import AutoComplete from './AutoComplete';
export default { export default {
name: 'Link', name: 'Link',
@ -84,12 +83,20 @@ export default {
}; };
}, },
async getFilters(keyword) { async getFilters(keyword) {
if (this.doc) { const { getFilters } = this.df;
return this.df.getFilters if (!getFilters) {
? (await this.df.getFilters(keyword, this.doc)) || {} return {};
: {}; }
if (this.doc) {
return (await getFilters(keyword, this.doc)) ?? {};
}
try {
return (await getFilters()) ?? {};
} catch {
return {};
} }
return {};
}, },
getTarget() { getTarget() {
return this.df.target; return this.df.target;

View File

@ -103,6 +103,14 @@
@change="(value) => doc.set('date', value)" @change="(value) => doc.set('date', value)"
:read-only="doc.submitted" :read-only="doc.submitted"
/> />
<FormControl
class="mt-2 text-base"
input-class="bg-gray-100 px-3 py-2 text-base text-right"
:df="meta.getField('numberSeries')"
:value="doc.numberSeries"
@change="(value) => doc.set('numberSeries', value)"
:read-only="doc.submitted"
/>
</div> </div>
</div> </div>
</div> </div>
@ -190,20 +198,20 @@
</div> </div>
</template> </template>
<script> <script>
import frappe from 'frappe'; import BackLink from '@/components/BackLink';
import StatusBadge from '@/components/StatusBadge';
import PageHeader from '@/components/PageHeader';
import Button from '@/components/Button'; import Button from '@/components/Button';
import FormControl from '@/components/Controls/FormControl'; import FormControl from '@/components/Controls/FormControl';
import DropdownWithActions from '@/components/DropdownWithActions'; import DropdownWithActions from '@/components/DropdownWithActions';
import BackLink from '@/components/BackLink'; import PageHeader from '@/components/PageHeader';
import StatusBadge from '@/components/StatusBadge';
import { import {
openSettings, getActionsForDocument,
getActionsForDocument, getInvoiceStatus,
getInvoiceStatus, openSettings,
showMessageDialog, routeTo,
routeTo, showMessageDialog
} from '@/utils'; } from '@/utils';
import frappe from 'frappe';
import { handleErrorWithDialog } from '../errorHandling'; import { handleErrorWithDialog } from '../errorHandling';
export default { export default {

View File

@ -35,7 +35,7 @@
<h1 class="text-2xl font-semibold"> <h1 class="text-2xl font-semibold">
{{ doc._notInserted ? t`New Journal Entry` : doc.name }} {{ doc._notInserted ? t`New Journal Entry` : doc.name }}
</h1> </h1>
<div class="flex justify-between mt-2"> <div class="flex justify-between mt-2 gap-2">
<div class="w-1/3"> <div class="w-1/3">
<FormControl <FormControl
:df="meta.getField('entryType')" :df="meta.getField('entryType')"
@ -78,6 +78,16 @@
:class="doc.submitted && 'pointer-events-none'" :class="doc.submitted && 'pointer-events-none'"
/> />
</div> </div>
<div class="w-1/3">
<FormControl
:df="meta.getField('numberSeries')"
:value="doc.numberSeries"
@change="(value) => doc.set('numberSeries', value)"
input-class="bg-gray-100 p-2 text-base"
:read-only="doc.submitted"
:class="doc.submitted && 'pointer-events-none'"
/>
</div>
</div> </div>
</div> </div>
<div class="mt-2 px-6 text-base"> <div class="mt-2 px-6 text-base">
@ -118,14 +128,14 @@
</div> </div>
</template> </template>
<script> <script>
import frappe from 'frappe';
import PageHeader from '@/components/PageHeader';
import Button from '@/components/Button';
import DropdownWithActions from '@/components/DropdownWithActions';
import FormControl from '@/components/Controls/FormControl';
import BackLink from '@/components/BackLink'; import BackLink from '@/components/BackLink';
import Button from '@/components/Button';
import FormControl from '@/components/Controls/FormControl';
import DropdownWithActions from '@/components/DropdownWithActions';
import PageHeader from '@/components/PageHeader';
import StatusBadge from '@/components/StatusBadge'; import StatusBadge from '@/components/StatusBadge';
import { showMessageDialog, getActionsForDocument, routeTo } from '@/utils'; import { getActionsForDocument, routeTo, showMessageDialog } from '@/utils';
import frappe from 'frappe';
import { handleErrorWithDialog } from '../errorHandling'; import { handleErrorWithDialog } from '../errorHandling';
export default { export default {

View File

@ -536,3 +536,23 @@ export function getCOAList() {
} }
return frappe.temp.coaList; return frappe.temp.coaList;
} }
export function invertMap(map) {
const keys = Object.keys(map);
const inverted = {};
for (const key of keys) {
const val = map[key];
inverted[val] = key;
}
return inverted;
}
export function getPaddedName(prefix, next, padZeros) {
const padding = padZeros ?? 4;
const l = next.toString().length;
const z = '0'.repeat(Math.max(0, padding - l));
return prefix + z + next;
}

View File

@ -12,20 +12,11 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"types": [ "types": ["webpack-env"],
"webpack-env"
],
"paths": { "paths": {
"@/*": [ "@/*": ["src/*"]
"src/*"
]
}, },
"lib": [ "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}, },
"include": [ "include": [
"src/**/*.ts", "src/**/*.ts",
@ -38,11 +29,10 @@
"frappe/**/*.ts", "frappe/**/*.ts",
"models/**/*.ts", "models/**/*.ts",
"patches/**/*.ts", "patches/**/*.ts",
"patches/**/*.js",
"reports/**/*.ts", "reports/**/*.ts",
"accounting/**/*.ts", "accounting/**/*.ts",
"accounting/**/*.ts", "accounting/**/*.ts"
], ],
"exclude": [ "exclude": ["node_modules"]
"node_modules"
]
} }