mirror of
https://github.com/frappe/books.git
synced 2024-11-13 00:46:28 +00:00
Add ability to cancel invoice
This commit is contained in:
parent
aa6a565f9b
commit
1ffd043ca9
@ -9,7 +9,8 @@ module.exports = {
|
|||||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
|
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||||
"arrow-body-style": "off",
|
"arrow-body-style": "off",
|
||||||
"prefer-arrow-callback": "off",
|
"prefer-arrow-callback": "off",
|
||||||
"vue/multi-word-component-names": "off"
|
"vue/multi-word-component-names": "off",
|
||||||
|
"vue/no-useless-template-attributes": "off",
|
||||||
},
|
},
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
parser: "@babel/eslint-parser"
|
parser: "@babel/eslint-parser"
|
||||||
|
@ -57,15 +57,12 @@ export default {
|
|||||||
fieldtype: 'Text',
|
fieldtype: 'Text',
|
||||||
placeholder: 'User Remark',
|
placeholder: 'User Remark',
|
||||||
},
|
},
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
{
|
||||||
label: 'Revert',
|
fieldname: 'cancelled',
|
||||||
condition: (doc) => doc.submitted,
|
label: 'Cancelled',
|
||||||
action(doc) {
|
fieldtype: 'Check',
|
||||||
doc.revert();
|
default: 0,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
ledgerLink,
|
|
||||||
],
|
],
|
||||||
|
actions: [ledgerLink],
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { _ } from 'frappejs/utils';
|
import { _ } from 'frappejs/utils';
|
||||||
|
import Badge from '@/components/Badge';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
doctype: 'JournalEntry',
|
doctype: 'JournalEntry',
|
||||||
@ -6,6 +7,29 @@ export default {
|
|||||||
formRoute: name => `/edit/JournalEntry/${name}`,
|
formRoute: name => `/edit/JournalEntry/${name}`,
|
||||||
columns: [
|
columns: [
|
||||||
'date',
|
'date',
|
||||||
|
{
|
||||||
|
label: 'Status',
|
||||||
|
fieldtype: 'Select',
|
||||||
|
size: 'small',
|
||||||
|
render(doc) {
|
||||||
|
let status = 'Draft';
|
||||||
|
let color = 'gray';
|
||||||
|
if (doc.submitted === 1) {
|
||||||
|
color = 'green';
|
||||||
|
status = 'Submitted';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.cancelled === 1) {
|
||||||
|
color = 'red';
|
||||||
|
status = 'Cancelled';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
template: `<Badge class="text-xs" color="${color}">${status}</Badge>`,
|
||||||
|
components: { Badge },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Entry ID',
|
label: 'Entry ID',
|
||||||
fieldname: 'name',
|
fieldname: 'name',
|
||||||
|
@ -140,6 +140,12 @@ export default {
|
|||||||
childtype: 'PaymentFor',
|
childtype: 'PaymentFor',
|
||||||
required: 0,
|
required: 0,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'cancelled',
|
||||||
|
label: 'Cancelled',
|
||||||
|
fieldtype: 'Check',
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
quickEditFields: [
|
quickEditFields: [
|
||||||
@ -206,16 +212,6 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [utils.ledgerLink],
|
||||||
{
|
|
||||||
label: 'Revert',
|
|
||||||
condition: (doc) => doc.submitted,
|
|
||||||
action(doc) {
|
|
||||||
doc.revert();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
utils.ledgerLink,
|
|
||||||
],
|
|
||||||
|
|
||||||
links: [utils.ledgerLink],
|
links: [utils.ledgerLink],
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,10 @@ export default {
|
|||||||
color = 'green';
|
color = 'green';
|
||||||
status = 'Submitted';
|
status = 'Submitted';
|
||||||
}
|
}
|
||||||
|
if (doc.cancelled === 1) {
|
||||||
|
color = 'red';
|
||||||
|
status = 'Cancelled';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
template: `<Badge class="text-xs" color="${color}">${status}</Badge>`,
|
template: `<Badge class="text-xs" color="${color}">${status}</Badge>`,
|
||||||
|
@ -123,6 +123,12 @@ export default {
|
|||||||
fieldname: 'terms',
|
fieldname: 'terms',
|
||||||
label: 'Terms',
|
label: 'Terms',
|
||||||
fieldtype: 'Text'
|
fieldtype: 'Text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'cancelled',
|
||||||
|
label: 'Cancelled',
|
||||||
|
fieldtype: 'Check',
|
||||||
|
default: 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -123,6 +123,12 @@ export default {
|
|||||||
label: 'Notes',
|
label: 'Notes',
|
||||||
fieldtype: 'Text',
|
fieldtype: 'Text',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldname: 'cancelled',
|
||||||
|
label: 'Cancelled',
|
||||||
|
fieldtype: 'Check',
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
actions: getActions('SalesInvoice'),
|
actions: getActions('SalesInvoice'),
|
||||||
|
@ -53,14 +53,6 @@ export function getActions(doctype) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Revert',
|
|
||||||
condition: (doc) =>
|
|
||||||
doc.submitted && doc.baseGrandTotal === doc.outstandingAmount,
|
|
||||||
action(doc) {
|
|
||||||
doc.revert();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Print',
|
label: 'Print',
|
||||||
condition: (doc) => doc.submitted,
|
condition: (doc) => doc.submitted,
|
||||||
|
@ -49,7 +49,11 @@ export default {
|
|||||||
const paymentEntries = await payment.getPosting();
|
const paymentEntries = await payment.getPosting();
|
||||||
await paymentEntries.postReverse();
|
await paymentEntries.postReverse();
|
||||||
// To set the payment status as unsubmitted.
|
// To set the payment status as unsubmitted.
|
||||||
payment.revert();
|
await frappe.db.update('Payment', {
|
||||||
|
name: paymentReference,
|
||||||
|
submitted: 0,
|
||||||
|
cancelled: 1,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const entries = await this.getPosting();
|
const entries = await this.getPosting();
|
||||||
await entries.postReverse();
|
await entries.postReverse();
|
||||||
|
@ -12,6 +12,7 @@ class Cashflow {
|
|||||||
let dateAsMonthYear = frappe.db.knex.raw('strftime("%m-%Y", ??)', 'date');
|
let dateAsMonthYear = frappe.db.knex.raw('strftime("%m-%Y", ??)', 'date');
|
||||||
let res = await frappe.db
|
let res = await frappe.db
|
||||||
.knex('AccountingLedgerEntry')
|
.knex('AccountingLedgerEntry')
|
||||||
|
.where('reverted', 0)
|
||||||
.sum({
|
.sum({
|
||||||
inflow: 'debit',
|
inflow: 'debit',
|
||||||
outflow: 'credit'
|
outflow: 'credit'
|
||||||
|
@ -60,8 +60,8 @@ const viewConfig = {
|
|||||||
{
|
{
|
||||||
fieldtype: 'Select',
|
fieldtype: 'Select',
|
||||||
options: [
|
options: [
|
||||||
{ label: 'Show Reverted', value: '' },
|
{ label: 'Show Cancelled', value: '' },
|
||||||
{ label: 'Hide Reverted', value: '0' }
|
{ label: 'Hide Cancelled', value: '0' }
|
||||||
],
|
],
|
||||||
size: 'small',
|
size: 'small',
|
||||||
default: '0',
|
default: '0',
|
||||||
|
56
src/utils.js
56
src/utils.js
@ -145,6 +145,40 @@ export function deleteDocWithPrompt(doc) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cancelDocWithPrompt(doc) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
showMessageDialog({
|
||||||
|
message: _('Are you sure you want to cancel {0} "{1}"?', [
|
||||||
|
doc.doctype,
|
||||||
|
doc.name,
|
||||||
|
]),
|
||||||
|
description: _('This action is permanent'),
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: _('Yes'),
|
||||||
|
async action() {
|
||||||
|
const entryDoc = await frappe.getDoc(doc.doctype, doc.name);
|
||||||
|
entryDoc.cancelled = 1;
|
||||||
|
await entryDoc.update();
|
||||||
|
entryDoc
|
||||||
|
.revert()
|
||||||
|
.then(() => resolve(true))
|
||||||
|
.catch((e) => {
|
||||||
|
handleErrorWithDialog(e, doc);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: _('No'),
|
||||||
|
action() {
|
||||||
|
resolve(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function partyWithAvatar(party) {
|
export function partyWithAvatar(party) {
|
||||||
return {
|
return {
|
||||||
data() {
|
data() {
|
||||||
@ -222,7 +256,7 @@ export function getActionsForDocument(doc) {
|
|||||||
component: {
|
component: {
|
||||||
template: `<span class="text-red-700">{{ _('Delete') }}</span>`,
|
template: `<span class="text-red-700">{{ _('Delete') }}</span>`,
|
||||||
},
|
},
|
||||||
condition: (doc) => !doc.isNew() && !doc.submitted && !doc.meta.isSingle,
|
condition: (doc) => !doc.isNew() && !doc.submitted && !doc.meta.isSingle && !doc.cancelled,
|
||||||
action: () =>
|
action: () =>
|
||||||
deleteDocWithPrompt(doc).then((res) => {
|
deleteDocWithPrompt(doc).then((res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
@ -231,7 +265,21 @@ export function getActionsForDocument(doc) {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let actions = [...(doc.meta.actions || []), deleteAction]
|
let cancelAction = {
|
||||||
|
component: {
|
||||||
|
template: `<span class="text-red-700">{{ _('Cancel') }}</span>`,
|
||||||
|
},
|
||||||
|
condition: (doc) => doc.submitted && !doc.cancelled,
|
||||||
|
action: () => {
|
||||||
|
cancelDocWithPrompt(doc).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
router.push(`/list/${doc.doctype}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let actions = [...(doc.meta.actions || []), deleteAction, cancelAction]
|
||||||
.filter((d) => (d.condition ? d.condition(doc) : true))
|
.filter((d) => (d.condition ? d.condition(doc) : true))
|
||||||
.map((d) => {
|
.map((d) => {
|
||||||
return {
|
return {
|
||||||
@ -270,6 +318,7 @@ export const statusColor = {
|
|||||||
Draft: 'gray',
|
Draft: 'gray',
|
||||||
Unpaid: 'orange',
|
Unpaid: 'orange',
|
||||||
Paid: 'green',
|
Paid: 'green',
|
||||||
|
Cancelled: 'red',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getInvoiceStatus(doc) {
|
export function getInvoiceStatus(doc) {
|
||||||
@ -280,5 +329,8 @@ export function getInvoiceStatus(doc) {
|
|||||||
if (doc.submitted === 1 && doc.outstandingAmount === 0.0) {
|
if (doc.submitted === 1 && doc.outstandingAmount === 0.0) {
|
||||||
status = 'Paid';
|
status = 'Paid';
|
||||||
}
|
}
|
||||||
|
if (doc.cancelled === 1) {
|
||||||
|
status = 'Cancelled';
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user