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

fix: db updation, invoice submit, number series

This commit is contained in:
18alantom 2022-05-02 15:45:16 +05:30
parent 185110276d
commit 8cc46c584c
24 changed files with 276 additions and 224 deletions

View File

@ -460,9 +460,8 @@ export default class DatabaseCore extends DatabaseBase {
let comparisonValue = value as string | number | (string | number)[];
if (Array.isArray(value)) {
operator = value[0] as string;
operator = (value[0] as string).toLowerCase();
comparisonValue = value[1] as string | number | (string | number)[];
operator = operator.toLowerCase();
if (operator === 'includes') {
operator = 'like';
@ -671,12 +670,12 @@ export default class DatabaseCore extends DatabaseBase {
idx: number
) {
if (!child.name) {
child.name = getRandomString();
child.name ??= getRandomString();
}
child.parent = parentName;
child.parentSchemaName = parentSchemaName;
child.parentFieldname = field.fieldname;
child.idx = idx;
child.idx ??= idx;
}
async #addForeignKeys(schemaName: string, newForeignKeys: Field[]) {
@ -878,14 +877,19 @@ export default class DatabaseCore extends DatabaseBase {
fieldValueMap: FieldValueMap,
isUpdate: boolean
) {
const parentName = fieldValueMap.name as string;
const tableFields = this.#getTableFields(schemaName);
const parentName = fieldValueMap.name as string;
for (const field of tableFields) {
const added: string[] = [];
const tableFieldValue = (fieldValueMap[field.fieldname] ??
[]) as FieldValueMap[];
const tableFieldValue = fieldValueMap[field.fieldname] as
| FieldValueMap[]
| undefined;
if (tableFieldValue === undefined) {
continue;
}
for (const child of tableFieldValue) {
this.#prepareChild(schemaName, parentName, child, field, added.length);

View File

@ -24,6 +24,12 @@ const Customer = {
fieldtype: 'Data',
placeholder: 'john@thoe.com',
},
{
fieldname: 'phone',
label: 'Phone',
fieldtype: 'Data',
placeholder: '9999999999',
},
],
quickEditFields: ['email'],
keywordFields: ['name'],

View File

@ -351,6 +351,26 @@ describe('DatabaseCore: CRUD', function () {
`email check update ${firstRow.email}`
);
const phone = '8149133530';
await sleep(1);
await db.update(schemaName, {
name,
phone,
modified: new Date().toISOString(),
});
rows = await db.knex!(schemaName);
firstRow = rows?.[0];
assert.strictEqual(
firstRow.email,
email,
`email check update ${firstRow.email}`
);
assert.strictEqual(
firstRow.phone,
phone,
`email check update ${firstRow.phone}`
);
for (const key in metaValues) {
const val = firstRow[key];
const expected = metaValues[key as BaseMetaKey];
@ -586,6 +606,17 @@ describe('DatabaseCore: CRUD', function () {
}
}
invoice.date = '2022-04-01';
invoice.modified = new Date().toISOString();
await db.update('SalesInvoice', {
name: invoice.name,
date: invoice.date,
modified: invoice.modified,
});
rows = await db.knex!(SalesInvoiceItem);
assert.strictEqual(rows.length, 2, `postupdate ct empty ${rows.length}`);
await db.delete(SalesInvoice, invoice.name as string);
rows = await db.getAll(SalesInvoiceItem);
assert.strictEqual(rows.length, 0, `ct length delete ${rows.length}`);

View File

@ -87,20 +87,6 @@ export class DocHandler {
return docMap?.[name];
}
getCachedValue(
schemaName: string,
name: string,
fieldname: string
): DocValue | Doc[] | undefined {
const docMap = this.docs[schemaName] as DocMap;
const doc = docMap[name];
if (doc === undefined) {
return;
}
return doc.get(fieldname);
}
isDirty(schemaName: string, name: string): boolean {
const doc = (this.docs?.[schemaName] as DocMap)?.[name];
if (doc === undefined) {

View File

@ -1,5 +1,6 @@
import { getMoneyMaker, MoneyMaker } from 'pesa';
import { Field } from 'schemas/types';
import { getIsNullOrUndef } from 'utils';
import { markRaw } from 'vue';
import { AuthHandler } from './core/authHandler';
import { DatabaseHandler } from './core/dbHandler';
@ -166,6 +167,30 @@ export class Fyo {
return schema?.fields.find((f) => f.fieldname === fieldname);
}
async getValue(
schemaName: string,
name: string,
fieldname?: string
): Promise<DocValue | Doc[]> {
if (fieldname === undefined && this.schemaMap[schemaName]?.isSingle) {
fieldname = name;
name = schemaName;
}
if (getIsNullOrUndef(name) || getIsNullOrUndef(fieldname)) {
return undefined;
}
let doc: Doc;
try {
doc = await this.doc.getDoc(schemaName, name);
} catch (err) {
return undefined;
}
return doc.get(fieldname!);
}
purgeCache() {
this.pesa = getMoneyMaker({
currency: DEFAULT_CURRENCY,

View File

@ -2,12 +2,7 @@ import { Fyo } from 'fyo';
import { DocValue, DocValueMap } from 'fyo/core/types';
import { Verb } from 'fyo/telemetry/types';
import { DEFAULT_USER } from 'fyo/utils/consts';
import {
ConflictError,
MandatoryError,
NotFoundError,
ValidationError
} from 'fyo/utils/errors';
import { ConflictError, MandatoryError, NotFoundError } from 'fyo/utils/errors';
import Observable from 'fyo/utils/observable';
import Money from 'pesa/dist/types/src/money';
import {
@ -25,7 +20,7 @@ import {
getMissingMandatoryMessage,
getPreDefaultValues,
setChildDocIdx,
shouldApplyFormula,
shouldApplyFormula
} from './helpers';
import { setName } from './naming';
import {
@ -42,7 +37,7 @@ import {
ReadOnlyMap,
RequiredMap,
TreeViewSettings,
ValidationMap,
ValidationMap
} from './types';
import { validateOptions, validateRequired } from './validationFunction';
@ -65,11 +60,6 @@ export class Doc extends Observable<DocValue | Doc[]> {
_dirty: boolean = true;
_notInserted: boolean = true;
flags = {
submitAction: false,
revertAction: false,
};
constructor(schema: Schema, data: DocValueMap, fyo: Fyo) {
super();
this.fyo = markRaw(fyo);
@ -469,21 +459,18 @@ export class Doc extends Observable<DocValue | Doc[]> {
this._notInserted = true;
}
_setChildIdx() {
_setChildDocsIdx() {
const childFields = this.schema.fields.filter(
(f) => f.fieldtype === FieldTypeEnum.Table
) as TargetField[];
for (const field of childFields) {
const childDocs = (this.get(field.fieldname) as Doc[]) ?? [];
for (let i = 0; i < childDocs.length; i++) {
childDocs[i].idx = i;
}
setChildDocIdx(childDocs);
}
}
async _compareWithCurrentDoc() {
async _validateDbNotModified() {
if (this.notInserted || !this.name || this.schema.isSingle) {
return;
}
@ -499,21 +486,6 @@ export class Doc extends Observable<DocValue | Doc[]> {
` ${dbModified}, ${docModified}`
);
}
if (this.submitted && !this.schema.isSubmittable) {
throw new ValidationError(
this.fyo.t`Document type ${this.schemaName} is not submittable`
);
}
// set submit action flag
if (this.submitted && !dbValues.submitted) {
this.flags.submitAction = true;
}
if (dbValues.submitted && !this.submitted) {
this.flags.revertAction = true;
}
}
async _applyFormula(fieldname?: string): Promise<boolean> {
@ -587,17 +559,16 @@ export class Doc extends Observable<DocValue | Doc[]> {
return value;
}
async _commit() {
// re-run triggers
this._setChildIdx();
async _preSync() {
this._setChildDocsIdx();
await this._applyFormula();
await this.trigger('validate', null);
await this.trigger('validate');
}
async _insert() {
await setName(this, this.fyo);
this._setBaseMetaValues();
await this._commit();
await this._preSync();
await this._validateInsert();
const oldName = this.name!;
@ -613,24 +584,14 @@ export class Doc extends Observable<DocValue | Doc[]> {
}
async _update() {
await this._compareWithCurrentDoc();
await this._commit();
// before submit
if (this.flags.submitAction) await this.trigger('beforeSubmit');
if (this.flags.revertAction) await this.trigger('beforeRevert');
// update modifiedBy and modified
await this._validateDbNotModified();
await this._preSync();
this._updateModifiedMetaValues();
const data = this.getValidDict();
await this.fyo.db.update(this.schemaName, data);
this._syncValues(data);
// after submit
if (this.flags.submitAction) await this.trigger('afterSubmit');
if (this.flags.revertAction) await this.trigger('afterRevert');
return this;
}
@ -657,29 +618,35 @@ export class Doc extends Observable<DocValue | Doc[]> {
this.fyo.doc.observer.trigger(`delete:${this.schemaName}`, this.name);
}
async _submitOrRevert(isSubmit: boolean) {
const wasSubmitted = this.submitted;
this.submitted = isSubmit;
try {
await this.sync();
} catch (e) {
this.submitted = wasSubmitted;
throw e;
}
}
async submit() {
this.cancelled = false;
await this._submitOrRevert(true);
if (!this.schema.isSubmittable || this.cancelled) {
return;
}
await this.trigger('beforeSubmit');
await this.setAndSync('submitted', true);
await this.trigger('afterSubmit');
this.fyo.doc.observer.trigger(`submit:${this.schemaName}`, this.name);
}
async revert() {
await this._submitOrRevert(false);
this.fyo.doc.observer.trigger(`revert:${this.schemaName}`, this.name);
async cancel() {
if (!this.schema.isSubmittable || !this.submitted) {
return;
}
await this.trigger('beforeCancel');
await this.setAndSync('cancelled', true);
await this.trigger('afterCancel');
this.fyo.doc.observer.trigger(`cancel:${this.schemaName}`, this.name);
}
async rename(newName: string) {
if (this.submitted) {
return;
}
await this.trigger('beforeRename');
await this.fyo.db.rename(this.schemaName, this.name!, newName);
this.name = newName;
@ -720,14 +687,6 @@ export class Doc extends Observable<DocValue | Doc[]> {
return sum;
}
getFrom(schemaName: string, name: string, fieldname: string) {
if (name === undefined || fieldname === undefined) {
return '';
}
return this.fyo.doc.getCachedValue(schemaName, name, fieldname);
}
async setAndSync(fieldname: string | DocValueMap, value?: DocValue | Doc[]) {
await this.set(fieldname, value);
return await this.sync();
@ -774,8 +733,8 @@ export class Doc extends Observable<DocValue | Doc[]> {
async afterDelete() {}
async beforeSubmit() {}
async afterSubmit() {}
async beforeRevert() {}
async afterRevert() {}
async beforeCancel() {}
async afterCancel() {}
formulas: FormulaMap = {};
validations: ValidationMap = {};

View File

@ -5,15 +5,17 @@ function getPaddedName(prefix: string, next: number, padZeros: number): string {
}
export default class NumberSeries extends Doc {
validate() {
const current = this.get('current') as number | null;
if (current) {
this.current = this.get('start');
setCurrent() {
let current = this.get('current') as number | null;
if (!current) {
current = this.get('start') as number;
}
this.current = current;
}
async next(schemaName: string) {
this.validate();
this.setCurrent();
const exists = await this.checkIfCurrentExists(schemaName);
if (!exists) {

View File

@ -3,7 +3,9 @@ import { Doc } from 'fyo/model/doc';
import { DefaultMap, FiltersMap, FormulaMap } from 'fyo/model/types';
import { getExchangeRate } from 'models/helpers';
import { LedgerPosting } from 'models/ledgerPosting/ledgerPosting';
import { ModelNameEnum } from 'models/types';
import Money from 'pesa/dist/types/src/money';
import { getIsNullOrUndef } from 'utils';
import { Party } from '../Party/Party';
import { Payment } from '../Payment/Payment';
import { Tax } from '../Tax/Tax';
@ -63,7 +65,7 @@ export abstract class Invoice extends Doc {
await party.updateOutstandingAmount();
}
async afterRevert() {
async afterCancel() {
const paymentRefList = await this.getPayments();
for (const paymentFor of paymentRefList) {
const paymentReference = paymentFor.parent;
@ -89,18 +91,20 @@ export abstract class Invoice extends Doc {
}
async getExchangeRate() {
if (!this.currency) return 1.0;
if (!this.currency) {
return 1.0;
}
const accountingSettings = await this.fyo.doc.getSingle(
'AccountingSettings'
const currency = await this.fyo.getValue(
ModelNameEnum.SystemSettings,
'currency'
);
const companyCurrency = accountingSettings.currency;
if (this.currency === companyCurrency) {
if (this.currency === currency) {
return 1.0;
}
return await getExchangeRate({
fromCurrency: this.currency!,
toCurrency: companyCurrency as string,
toCurrency: currency as string,
});
}
@ -163,14 +167,28 @@ export abstract class Invoice extends Doc {
formulas: FormulaMap = {
account: {
formula: async () =>
this.getFrom('Party', this.party!, 'defaultAccount') as string,
formula: async () => {
return (await this.fyo.getValue(
'Party',
this.party!,
'defaultAccount'
)) as string;
},
dependsOn: ['party'],
},
currency: {
formula: async () =>
(this.getFrom('Party', this.party!, 'currency') as string) ||
(this.fyo.singles.AccountingSettings!.currency as string),
formula: async () => {
const currency = (await this.fyo.getValue(
'Party',
this.party!,
'currency'
)) as string;
if (!getIsNullOrUndef(currency)) {
return currency;
}
return this.fyo.singles.SystemSettings!.currency as string;
},
dependsOn: ['party'],
},
exchangeRate: { formula: async () => await this.getExchangeRate() },
@ -199,6 +217,9 @@ export abstract class Invoice extends Doc {
};
static filters: FiltersMap = {
party: (doc: Doc) => ({
role: ['in', [doc.isSales ? 'Customer' : 'Supplier', 'Both']],
}),
account: (doc: Doc) => ({
isGroup: false,
accountType: doc.isSales ? 'Receivable' : 'Payable',

View File

@ -17,23 +17,23 @@ export abstract class InvoiceItem extends Doc {
formulas: FormulaMap = {
description: {
formula: () =>
this.parentdoc!.getFrom(
formula: async () =>
(await this.fyo.getValue(
'Item',
this.item as string,
'description'
) as string,
)) as string,
dependsOn: ['item'],
},
rate: {
formula: async () => {
const baseRate = ((await this.parentdoc!.getFrom(
const rate = (await this.fyo.getValue(
'Item',
this.item as string,
'rate'
)) || this.fyo.pesa(0)) as Money;
)) as undefined | Money;
return baseRate.div(this.exchangeRate!);
return rate ?? this.fyo.pesa(0);
},
dependsOn: ['item'],
},
@ -48,25 +48,17 @@ export abstract class InvoiceItem extends Doc {
if (this.isSales) {
accountType = 'incomeAccount';
}
return this.parentdoc!.getFrom(
'Item',
this.item as string,
accountType
);
return this.fyo.getValue('Item', this.item as string, accountType);
},
dependsOn: ['item'],
},
tax: {
formula: () => {
if (this.tax) {
return this.tax as string;
}
return this.parentdoc!.getFrom(
formula: async () => {
return (await this.fyo.getValue(
'Item',
this.item as string,
'tax'
) as string;
)) as string;
},
dependsOn: ['item'],
},
@ -80,8 +72,8 @@ export abstract class InvoiceItem extends Doc {
dependsOn: ['item', 'amount', 'rate', 'quantity'],
},
hsnCode: {
formula: () =>
this.parentdoc!.getFrom('Item', this.item as string, 'hsnCode'),
formula: async () =>
await this.fyo.getValue('Item', this.item as string, 'hsnCode'),
dependsOn: ['item'],
},
};

View File

@ -40,7 +40,7 @@ export class JournalEntry extends Doc {
await this.getPosting().post();
}
async afterRevert() {
async afterCancel() {
await this.getPosting().postReverse();
}

View File

@ -69,14 +69,17 @@ export class Party extends Doc {
dependsOn: ['role'],
},
currency: {
formula: async () =>
this.fyo.singles.AccountingSettings!.currency as string,
formula: async () => this.fyo.singles.SystemSettings!.currency as string,
},
address: {
formula: async () => {
const address = this.address as string | undefined;
if (address) {
return this.getFrom('Address', address, 'addressDisplay') as string;
return (await this.fyo.getValue(
'Address',
address,
'addressDisplay'
)) as string;
}
return '';
},

View File

@ -256,7 +256,7 @@ export class Payment extends Doc {
}
}
async afterRevert() {
async afterCancel() {
this.updateReferenceOutstandingAmount();
const entryList = await this.getPosting();
for (const entry of entryList) {
@ -391,11 +391,11 @@ export class Payment extends Doc {
render(doc) {
let status = 'Draft';
let color = 'gray';
if (doc.submitted === 1) {
if (doc.submitted) {
color = 'green';
status = 'Submitted';
}
if (doc.cancelled === 1) {
if (doc.cancelled) {
color = 'red';
status = 'Cancelled';
}

View File

@ -10,11 +10,11 @@ export class PaymentFor extends Doc {
return this.fyo.pesa(0);
}
const outstandingAmount = this.parentdoc!.getFrom(
const outstandingAmount = (await this.fyo.getValue(
this.referenceType as string,
this.referenceName as string,
'outstandingAmount'
) as Money;
)) as Money;
if (outstandingAmount) {
return outstandingAmount;

View File

@ -15,6 +15,28 @@
"label": "Image",
"fieldtype": "AttachImage"
},
{
"fieldname": "role",
"label": "Role",
"fieldtype": "Select",
"default": "Both",
"options": [
{
"value": "Both",
"label": "Both"
},
{
"value": "Supplier",
"label": "Supplier"
},
{
"value": "Customer",
"label": "Customer"
}
],
"readOnly": true,
"required": true
},
{
"fieldname": "defaultAccount",
"label": "Default Account",

View File

@ -31,14 +31,14 @@ describe('Schema Builder', function () {
assert.strictEqual(appSchemaMap.Account.fields?.length, 6);
assert.strictEqual(appSchemaMap.JournalEntry.fields?.length, 8);
assert.strictEqual(appSchemaMap.JournalEntryAccount.fields?.length, 3);
assert.strictEqual(appSchemaMap.Party.fields?.length, 8);
assert.strictEqual(appSchemaMap.Party.fields?.length, 9);
assert.strictEqual(appSchemaMap.Customer.fields?.length, undefined);
assert.strictEqual(regionalSchemaMap.Party.fields?.length, 2);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(appSchemaMap.Party.quickEditFields?.length, 5);
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 7);
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 8);
});
});
@ -48,11 +48,11 @@ describe('Schema Builder', function () {
);
describe('Regional Combined Schemas', function () {
specify('Field Counts', function () {
assert.strictEqual(regionalCombined.Party.fields?.length, 10);
assert.strictEqual(regionalCombined.Party.fields?.length, 11);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 7);
assert.strictEqual(regionalSchemaMap.Party.quickEditFields?.length, 8);
});
specify('Schema Equality with App Schemas', function () {
@ -95,11 +95,11 @@ describe('Schema Builder', function () {
});
specify('Field Counts', function () {
assert.strictEqual(abstractCombined.Customer!.fields?.length, 10);
assert.strictEqual(abstractCombined.Customer!.fields?.length, 11);
});
specify('Quick Edit Field Counts', function () {
assert.strictEqual(abstractCombined.Customer!.quickEditFields?.length, 7);
assert.strictEqual(abstractCombined.Customer!.quickEditFields?.length, 8);
});
specify('Schema Equality with App Schemas', function () {

View File

@ -23,6 +23,7 @@
>
<input
ref="input"
spellcheck="false"
:class="inputClasses"
type="text"
:value="linkValue"

View File

@ -4,6 +4,7 @@
{{ df.label }}
</div>
<input
spellcheck="false"
ref="input"
:class="inputClasses"
:type="inputType"

View File

@ -144,7 +144,7 @@ export default {
return (this.maxHeight = '');
}
const rowHeight = this.$refs?.['table-row']?.[0].$el.offsetHeight;
const rowHeight = this.$refs?.['table-row']?.[0]?.$el.offsetHeight;
if (rowHeight === undefined) {
return (this.maxHeight = '');
}

View File

@ -1,46 +1,52 @@
<template>
<div class="py-4" v-if="pendingInvoices.length">
<div class="px-4 text-sm text-gray-600 mb-1">
<div class="px-4 text-sm text-gray-600">
{{ t`Recent Invoices` }}
</div>
<!-- Invoice List -->
<div
class="px-4 py-3 border-b hover:bg-gray-100 cursor-pointer"
class="px-4 py-3 border-b hover:bg-gray-100 cursor-pointer text-base"
v-for="invoice in pendingInvoices"
:key="invoice.name"
@click="routeToForm(invoice)"
>
<div class="text-base">
<div class="flex justify-between items-center mb-1">
<span class="font-medium">
{{ invoice.name }}
<!-- Invoice Name & Status -->
<div class="flex justify-between items-center mb-1">
<span class="font-medium">
{{ invoice.name }}
</span>
<span>
<component :is="getStatusBadge(invoice)" />
</span>
</div>
<!-- Invoice Date & Amount -->
<div class="flex justify-between">
<span>
{{ fyo.format(invoice.date, getInvoiceField(invoice, 'date')) }}
</span>
<div>
<!-- Paid Amount -->
<span class="font-medium text-gray-900">
{{
fyo.format(
amountPaid(invoice),
getInvoiceField(invoice, 'baseGrandTotal')
)
}}
</span>
<span>
<component :is="getStatusBadge(invoice)" />
<!-- Outstanding Amount -->
<span class="text-gray-600" v-if="!fullyPaid(invoice)">
({{
fyo.format(
invoice.outstandingAmount,
getInvoiceField(invoice, 'outstandingAmount')
)
}})
</span>
</div>
<div class="flex justify-between">
<span>
{{ fyo.format(invoice.date, getInvoiceField(invoice, 'date')) }}
</span>
<div>
<span class="font-medium text-gray-900">
{{
fyo.format(
amountPaid(invoice),
getInvoiceField(invoice, 'baseGrandTotal')
)
}}
</span>
<span class="text-gray-600" v-if="!fullyPaid(invoice)">
({{
fyo.format(
invoice.outstandingAmount,
getInvoiceField(invoice, 'outstandingAmount')
)
}})
</span>
</div>
</div>
</div>
</div>
</div>
@ -52,7 +58,7 @@ import { PartyRoleEnum } from 'models/baseModels/Party/types';
import { getTransactionStatusColumn } from 'models/helpers';
import { ModelNameEnum } from 'models/types';
import { fyo } from 'src/initFyo';
import { routeTo } from 'src/utils';
import { routeTo } from 'src/utils/ui';
export default {
name: 'PartyWidget',

View File

@ -13,18 +13,18 @@
</Button>
<DropdownWithActions :actions="actions" />
<Button
v-if="showSave"
v-if="doc?.notInserted || doc?.dirty"
type="primary"
class="text-white text-xs"
@click="onSaveClick"
@click="sync"
>
{{ t`Save` }}
</Button>
<Button
v-if="!doc.dirty && !doc.notInserted && !doc?.submitted"
v-if="!doc?.dirty && !doc?.notInserted && !doc?.submitted"
type="primary"
class="text-white text-xs"
@click="onSubmitClick"
@click="submit"
>{{ t`Submit` }}</Button
>
</PageHeader>
@ -155,7 +155,7 @@
/>
<!-- Totals -->
<div class="w-1/2 gap-2 flex flex-col self-end">
<div class="w-1/2 gap-2 flex flex-col self-end ml-auto">
<!-- Subtotal -->
<div class="flex justify-between">
<div>{{ t`Subtotal` }}</div>
@ -267,9 +267,6 @@ export default {
address() {
return this.printSettings && this.printSettings.getLink('address');
},
showSave() {
return this.doc && (this.doc.notInserted || this.doc.dirty);
},
actions() {
return getActionsForDocument(this.doc);
},
@ -307,15 +304,11 @@ export default {
getField(fieldname) {
return fyo.getField(this.schemaName, fieldname);
},
async onSaveClick() {
await this.doc.set(
'items',
this.doc.items.filter((row) => row.item)
);
async sync() {
return this.doc.sync().catch(this.handleError);
},
onSubmitClick() {
let message =
submit() {
const message =
this.schemaName === ModelNameEnum.SalesInvoice
? this.t`Are you sure you want to submit this Sales Invoice?`
: this.t`Are you sure you want to submit this Purchase Invoice?`;

View File

@ -6,7 +6,7 @@
<StatusBadge :status="status" />
<DropdownWithActions :actions="actions" />
<Button
v-if="doc.notInserted || doc.dirty"
v-if="doc?.notInserted || doc?.dirty"
type="primary"
class="text-white text-xs"
@click="sync"
@ -120,6 +120,7 @@
<div class="flex justify-between text-base m-6 gap-12">
<!-- User Remark -->
<FormControl
v-if="!doc.submitted || doc.userRemark"
class="w-1/2 self-end"
input-class="bg-gray-100"
:df="getField('userRemark')"
@ -130,7 +131,9 @@
/>
<!-- Debit and Credit -->
<div class="w-1/2 gap-2 flex flex-col self-end font-semibold">
<div
class="w-1/2 gap-2 flex flex-col self-end font-semibold ml-auto"
>
<div class="flex justify-between text-green-600">
<div>{{ t`Total Debit` }}</div>
<div>{{ totalDebit }}</div>
@ -158,9 +161,9 @@ import PageHeader from 'src/components/PageHeader';
import StatusBadge from 'src/components/StatusBadge';
import { fyo } from 'src/initFyo';
import {
getActionsForDocument,
routeTo,
showMessageDialog
getActionsForDocument,
routeTo,
showMessageDialog,
} from 'src/utils/ui';
import { handleErrorWithDialog } from '../errorHandling';
@ -173,8 +176,8 @@ export default {
DropdownWithActions,
StatusBadge,
FormControl,
Table
},
Table,
},
provide() {
return {
schemaName: this.schemaName,

View File

@ -48,10 +48,10 @@
<script>
import { ipcRenderer } from 'electron';
import { Verb } from 'fyo/telemetry/types';
import Button from 'src/components/Button';
import PageHeader from 'src/components/PageHeader';
import SearchBar from 'src/components/SearchBar';
import TwoColumnForm from 'src/components/TwoColumnForm';
import Button from 'src/components/Button.vue';
import PageHeader from 'src/components/PageHeader.vue';
import InvoiceTemplate from 'src/components/SalesInvoice/InvoiceTemplate.vue';
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
import { makePDF } from 'src/utils';
import { IPC_ACTIONS } from 'utils/messages';
@ -60,7 +60,6 @@ export default {
props: { schemaName: String, name: String },
components: {
PageHeader,
SearchBar,
Button,
TwoColumnForm,
},
@ -73,14 +72,11 @@ export default {
},
async mounted() {
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
this.printSettings = await fyo.getSingle('PrintSettings');
this.printSettings = await fyo.doc.getSingle('PrintSettings');
},
computed: {
meta() {
return fyo.getMeta(this.schemaName);
},
printTemplate() {
return this.meta.printTemplate;
return InvoiceTemplate
},
},
methods: {

View File

@ -130,7 +130,7 @@ function getReportList(): SearchItem[] {
}
function getListViewList(): SearchItem[] {
const standardLists = [
let schemaNames = [
ModelNameEnum.Account,
ModelNameEnum.Party,
ModelNameEnum.Payment,
@ -138,7 +138,12 @@ function getListViewList(): SearchItem[] {
ModelNameEnum.PurchaseInvoice,
ModelNameEnum.SalesInvoice,
ModelNameEnum.Tax,
]
];
if (fyo.store.isDevelopment) {
schemaNames = Object.keys(fyo.schemaMap) as ModelNameEnum[];
}
const standardLists = schemaNames
.map((s) => fyo.schemaMap[s])
.filter((s) => s && !s.isChild && !s.isSingle)
.map(

View File

@ -214,14 +214,10 @@ export async function cancelDocWithPrompt(doc: Doc) {
label: t`Yes`,
async action() {
const entryDoc = await fyo.doc.getDoc(doc.schemaName, doc.name!);
entryDoc.cancelled = 1;
await entryDoc.sync();
entryDoc
.revert()
.cancel()
.then(() => resolve(true))
.catch((e) => {
handleErrorWithDialog(e, doc);
});
.catch((e) => handleErrorWithDialog(e, doc));
},
},
{
@ -262,7 +258,7 @@ function getCancelAction(doc: Doc): Action {
component: {
template: '<span class="text-red-700">{{ t`Cancel` }}</span>',
},
condition: (doc: Doc) => !!(doc.submitted && !doc.cancelled),
condition: (doc: Doc) => !doc.cancelled,
action: () => {
cancelDocWithPrompt(doc).then((res) => {
if (res) {