2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 19:09:01 +00:00

Add ability to cancel invoice

This commit is contained in:
Piyush Singhania 2021-11-21 19:08:04 +05:30
parent aa6a565f9b
commit 1ffd043ca9
12 changed files with 116 additions and 33 deletions

View File

@ -9,7 +9,8 @@ module.exports = {
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
"arrow-body-style": "off",
"prefer-arrow-callback": "off",
"vue/multi-word-component-names": "off"
"vue/multi-word-component-names": "off",
"vue/no-useless-template-attributes": "off",
},
parserOptions: {
parser: "@babel/eslint-parser"

View File

@ -57,15 +57,12 @@ export default {
fieldtype: 'Text',
placeholder: 'User Remark',
},
],
actions: [
{
label: 'Revert',
condition: (doc) => doc.submitted,
action(doc) {
doc.revert();
},
fieldname: 'cancelled',
label: 'Cancelled',
fieldtype: 'Check',
default: 0,
},
ledgerLink,
],
actions: [ledgerLink],
};

View File

@ -1,4 +1,5 @@
import { _ } from 'frappejs/utils';
import Badge from '@/components/Badge';
export default {
doctype: 'JournalEntry',
@ -6,6 +7,29 @@ export default {
formRoute: name => `/edit/JournalEntry/${name}`,
columns: [
'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',
fieldname: 'name',

View File

@ -140,6 +140,12 @@ export default {
childtype: 'PaymentFor',
required: 0,
},
{
fieldname: 'cancelled',
label: 'Cancelled',
fieldtype: 'Check',
default: 0,
},
],
quickEditFields: [
@ -206,16 +212,6 @@ export default {
],
},
],
actions: [
{
label: 'Revert',
condition: (doc) => doc.submitted,
action(doc) {
doc.revert();
},
},
utils.ledgerLink,
],
actions: [utils.ledgerLink],
links: [utils.ledgerLink],
};

View File

@ -21,6 +21,10 @@ export default {
color = 'green';
status = 'Submitted';
}
if (doc.cancelled === 1) {
color = 'red';
status = 'Cancelled';
}
return {
template: `<Badge class="text-xs" color="${color}">${status}</Badge>`,

View File

@ -123,6 +123,12 @@ export default {
fieldname: 'terms',
label: 'Terms',
fieldtype: 'Text'
},
{
fieldname: 'cancelled',
label: 'Cancelled',
fieldtype: 'Check',
default: 0
}
],

View File

@ -123,6 +123,12 @@ export default {
label: 'Notes',
fieldtype: 'Text',
},
{
fieldname: 'cancelled',
label: 'Cancelled',
fieldtype: 'Check',
default: 0,
},
],
actions: getActions('SalesInvoice'),

View File

@ -53,14 +53,6 @@ export function getActions(doctype) {
});
},
},
{
label: 'Revert',
condition: (doc) =>
doc.submitted && doc.baseGrandTotal === doc.outstandingAmount,
action(doc) {
doc.revert();
},
},
{
label: 'Print',
condition: (doc) => doc.submitted,

View File

@ -49,7 +49,11 @@ export default {
const paymentEntries = await payment.getPosting();
await paymentEntries.postReverse();
// 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();
await entries.postReverse();

View File

@ -12,6 +12,7 @@ class Cashflow {
let dateAsMonthYear = frappe.db.knex.raw('strftime("%m-%Y", ??)', 'date');
let res = await frappe.db
.knex('AccountingLedgerEntry')
.where('reverted', 0)
.sum({
inflow: 'debit',
outflow: 'credit'

View File

@ -60,8 +60,8 @@ const viewConfig = {
{
fieldtype: 'Select',
options: [
{ label: 'Show Reverted', value: '' },
{ label: 'Hide Reverted', value: '0' }
{ label: 'Show Cancelled', value: '' },
{ label: 'Hide Cancelled', value: '0' }
],
size: 'small',
default: '0',

View File

@ -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) {
return {
data() {
@ -222,7 +256,7 @@ export function getActionsForDocument(doc) {
component: {
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: () =>
deleteDocWithPrompt(doc).then((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))
.map((d) => {
return {
@ -270,6 +318,7 @@ export const statusColor = {
Draft: 'gray',
Unpaid: 'orange',
Paid: 'green',
Cancelled: 'red',
};
export function getInvoiceStatus(doc) {
@ -280,5 +329,8 @@ export function getInvoiceStatus(doc) {
if (doc.submitted === 1 && doc.outstandingAmount === 0.0) {
status = 'Paid';
}
if (doc.cancelled === 1) {
status = 'Cancelled';
}
return status;
}